概览

此视图显示FlexGrid控件的基本功能。它将网格绑定到数据源,并具有下面的菜单,允许您选择数据项的数量,选择模式文化,以及是否使用数据映射和格式。请注意,即使有大量数据项,网格仍然保持快速流畅。 FlexGrid通过自动虚拟化行和列来实现此级别的性能。

您可以使用键盘和鼠标选择单元格和范围。当前选择会自动在屏幕上更新。使用下面的“选择”菜单尝试各种选择模式。请注意,ListBox模式允许您选择不连续的行。

您可以通过拖动鼠标来调整大小和移动列,并通过双击列标题的右边缘自动调整列的大小。如果在调整所选列的大小时按控制键,则会调整所有选定列的大小。

您可以通过单击列标题对列进行排序。单击列标题时按控制键以删除排序。

网格上方的过滤器和导航栏允许您过滤和浏览数据。两者都使用ICollectionView接口实现,就像在C#和.NET中一样。

请注意,与标准的AngularJS搜索过滤器不同,此过滤器支持多项搜索,因此如果您键入 us gad red,则网格会显示包含 所有 这些项的项目(国家/地区为“US”,产品是'Gadget',颜色是'红色')。

底部的按钮演示了列和行的isVisible属性,以及列宽和行高属性,如以及FlexGridscrollPosition属性。

import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './styles.css'; import * as wjCore from '@grapecity/wijmo'; import * as wjInput from '@grapecity/wijmo.input'; import * as wjGrid from '@grapecity/wijmo.grid'; import { getData, getColors, getCountries, getProducts } from './data'; document.readyState === 'complete' ? init() : window.onload = init; function init() { // bind a grid to the data let theGrid = new wjGrid.FlexGrid('#theGrid'); theGrid.select(new wjGrid.CellRange(0, 0)); theGrid.selectionChanged.addHandler((s, e) => { document.querySelector('#cellRange').innerHTML = formatCellRange(e.range); }); let toFilter; document.querySelector('#filter').addEventListener('keyup', () => { if (toFilter) { clearTimeout(toFilter); } toFilter = setTimeout(function () { toFilter = null; if (theGrid) { let cv = theGrid.collectionView; if (cv) { if (cv.filter != filterFunction) { cv.filter = filterFunction; } else { cv.refresh(); } } } }, 500); }); document.querySelector('#first').addEventListener('click', () => { theGrid.collectionView.moveCurrentToFirst(); }); document.querySelector('#previous').addEventListener('click', () => { theGrid.collectionView.moveCurrentToPrevious(); }); document.querySelector('#next').addEventListener('click', () => { theGrid.collectionView.moveCurrentToNext(); }); document.querySelector('#last').addEventListener('click', () => { theGrid.collectionView.moveCurrentToLast(); }); // create item count menu let itemCountMenu = new wjInput.Menu('#itemCountMenu', { // update header to show current selection selectedIndexChanged: function (s, e) { if (s.selectedIndex > -1) { formatMenuHeader(s); theGrid.itemsSource = getData(s.selectedValue, currentItemChanged.bind(this)); if (dataMapsMenu) { updateDataMaps(dataMapsMenu.selectedValue); } if (formattingMenu) { updateFormatting(formattingMenu.selectedValue); } currentItemChanged(); } }, header: 'Items', displayMemberPath: 'header', selectedValuePath: 'value', itemsSource: [ { header: '5', value: 5 }, { header: '50', value: 50 }, { header: '500', value: 500 }, { header: '5,000', value: 5000 }, { header: '50,000', value: 50000 }, { header: '100,000', value: 100000 }, { header: '500,000', value: 500000 }, { header: '1,000,000', value: 1000000 } ] }); // initialize value itemCountMenu.selectedValue = 500; // create allow add new menu let allowAddNewMenu = new wjInput.Menu('#allowAddNewMenu', { // update header to show current selection selectedIndexChanged: function (s, e) { if (s.selectedIndex > -1) { formatMenuHeader(s); theGrid.allowAddNew = s.selectedValue; } }, header: 'Allow Add', displayMemberPath: 'header', selectedValuePath: 'value', itemsSource: [ { header: 'Yes', value: true }, { header: 'No', value: false } ] }); // initialize value allowAddNewMenu.selectedValue = false; // create selection mode menu let selectionModeMenu = new wjInput.Menu('#selectionModeMenu', { // update header to show current selection selectedIndexChanged: function (s, e) { if (s.selectedIndex > -1) { formatMenuHeader(s); theGrid.selectionMode = s.selectedValue; } }, header: 'Selection', displayMemberPath: 'header', selectedValuePath: 'value', itemsSource: [ { header: 'None', value: wjGrid.SelectionMode.None }, { header: 'Cell', value: wjGrid.SelectionMode.Cell }, { header: 'CellRange', value: wjGrid.SelectionMode.CellRange }, { header: 'Row', value: wjGrid.SelectionMode.Row }, { header: 'RowRange', value: wjGrid.SelectionMode.RowRange }, { header: 'ListBox', value: wjGrid.SelectionMode.ListBox } ] }); // initialize value selectionModeMenu.selectedValue = wjGrid.SelectionMode.CellRange; theGrid.selection = new wjGrid.CellRange(0, 0); // create header visibility menu let headersVisibilityMenu = new wjInput.Menu('#headersVisibilityMenu', { // update header to show current selection selectedIndexChanged: function (s, e) { if (s.selectedIndex > -1) { formatMenuHeader(s); theGrid.headersVisibility = s.selectedValue; } }, header: 'Headers Visibility', displayMemberPath: 'header', selectedValuePath: 'value', itemsSource: [ { header: 'None', value: wjGrid.HeadersVisibility.None }, { header: 'Column', value: wjGrid.HeadersVisibility.Column }, { header: 'Row', value: wjGrid.HeadersVisibility.Row }, { header: 'All', value: wjGrid.HeadersVisibility.All } ] }); // initialize value headersVisibilityMenu.selectedValue = wjGrid.HeadersVisibility.All; // create show selected headers menu let showSelectedHeadersMenu = new wjInput.Menu('#showSelectedHeadersMenu', { // update header to show current selection selectedIndexChanged: function (s, e) { if (s.selectedIndex > -1) { formatMenuHeader(s); theGrid.showSelectedHeaders = s.selectedValue; } }, header: 'Show Selected Headers', displayMemberPath: 'header', selectedValuePath: 'value', itemsSource: [ { header: 'None', value: wjGrid.HeadersVisibility.None }, { header: 'Column', value: wjGrid.HeadersVisibility.Column }, { header: 'Row', value: wjGrid.HeadersVisibility.Row }, { header: 'All', value: wjGrid.HeadersVisibility.All } ] }); // initialize value showSelectedHeadersMenu.selectedValue = wjGrid.HeadersVisibility.None; // create Show Marquee menu let showMarqueeMenu = new wjInput.Menu('#showMarqueeMenu', { // update header to show current selection selectedIndexChanged: function (s, e) { if (s.selectedIndex > -1) { formatMenuHeader(s); theGrid.showMarquee = s.selectedValue; } }, header: 'Show Marquee', displayMemberPath: 'header', selectedValuePath: 'value', itemsSource: [ { header: 'On', value: true }, { header: 'Off', value: false } ] }); // initialize value showMarqueeMenu.selectedValue = false; // create Data Maps menu let dataMapsMenu = new wjInput.Menu('#dataMapsMenu', { // update header to show current selection selectedIndexChanged: function (s, e) { if (s.selectedIndex > -1) { formatMenuHeader(s); updateDataMaps(s.selectedValue); } }, header: 'Data Maps', displayMemberPath: 'header', selectedValuePath: 'value', itemsSource: [ { header: 'On', value: true }, { header: 'Off', value: false } ] }); // initialize value dataMapsMenu.selectedValue = true; // create Formatting menu let formattingMenu = new wjInput.Menu('#formattingMenu', { // update header to show current selection selectedIndexChanged: function (s, e) { if (s.selectedIndex > -1) { formatMenuHeader(s); updateFormatting(s.selectedValue); } }, header: 'Formatting', displayMemberPath: 'header', selectedValuePath: 'value', itemsSource: [ { header: 'On', value: true }, { header: 'Off', value: false } ] }); // initialize value formattingMenu.selectedValue = true; // Create Culture menu /*var cultureMenu = new wjInput.Menu('#cultureMenu', { header: 'Culture', displayMemberPath: 'header', selectedValuePath: 'value', itemsSource: [ { header: 'English', value: 'en' }, { header: 'Spanish', value: 'es' }, { header: 'Italian', value: 'it' }, { header: 'French', value: 'fr' }, { header: 'German', value: 'de' }, { header: 'Dutch', value: 'nl' }, { header: 'Japanese', value: 'ja' }, { header: 'Korean', value: 'ko' }, { header: 'Chinese', value: 'zh-HK' }, ], selectedIndexChanged: function(s, e) { if (s.selectedIndex > -1){ formatMenuHeader(s); loadCulture(s.selectedValue); } } }); cultureMenu.selectedValue = 'en';*/ document.querySelector('#toggleColumnVisibility').addEventListener('click', () => { let col = theGrid.columns[0]; col.visible = !col.visible; }); document.querySelector('#changeColumnSize').addEventListener('click', () => { let col = theGrid.columns[0]; col.visible = true; col.width = col.width < 0 ? 60 : -1; col = theGrid.rowHeaders.columns[0]; col.width = col.width < 0 ? 40 : -1; }); document.querySelector('#toggleRowVisibility').addEventListener('click', () => { let row = theGrid.rows[0]; row.visible = !row.visible; }); document.querySelector('#changeRowSize').addEventListener('click', () => { let row = theGrid.rows[0]; row.visible = true; row.height = row.height < 0 ? 80 : -1; row = theGrid.columnHeaders.rows[0]; row.height = row.height < 0 ? 80 : -1; }); document.querySelector('#changeDefaultRowSize').addEventListener('click', () => { theGrid.rows.defaultSize = theGrid.rows.defaultSize == 28 ? 65 : 28; }); document.querySelector('#changeScrollPosition').addEventListener('click', () => { if (theGrid.scrollPosition.y == 0) { var sz = theGrid.scrollSize; theGrid.scrollPosition = new wjCore.Point(-sz.width / 2, -sz.height / 2); } else { theGrid.scrollPosition = new wjCore.Point(0, 0); } }); function formatMenuHeader(menu) { let index = menu.header.indexOf(':'); if (index !== -1) { menu.header = menu.header.substring(0, menu.header.indexOf(':')) + wjCore.format(': <b>{header}</b>', menu.selectedItem); } else { menu.header = menu.header + wjCore.format(': <b>{header}</b>', menu.selectedItem); } } // apply/remove data maps function updateDataMaps(dataMaps) { if (theGrid) { var colCountry = theGrid.columns.getColumn('countryId'); var colProduct = theGrid.columns.getColumn('productId'); var colColor = theGrid.columns.getColumn('colorId'); if (colCountry && colProduct && colColor) { if (dataMaps) { colCountry.showDropDown = true; // show drop-down for countries colProduct.showDropDown = false; // don't show it for products colColor.showDropDown = false; // or colors (just to show how) colCountry.dataMap = buildDataMap(getCountries()); colProduct.dataMap = buildDataMap(getProducts()); colColor.dataMap = buildDataMap(getColors()); } else { colCountry.dataMap = null; colProduct.dataMap = null; colColor.dataMap = null; } } } } // build a data map from a string array using the indices as keys function buildDataMap(items) { var map = []; for (var i = 0; i < items.length; i++) { map.push({ key: i, value: items[i] }); } return new wjGrid.DataMap(map, 'key', 'value'); } // apply/remove column formatting function updateFormatting(fmt) { if (theGrid) { setColumnFormat('amount', fmt ? 'c' : null); setColumnFormat('amount2', fmt ? 'c' : null); setColumnFormat('discount', fmt ? 'p0' : null); setColumnFormat('start', fmt ? 'MMM d yy' : null); setColumnFormat('end', fmt ? 'HH:mm' : null); } } function setColumnFormat(name, format) { var col = theGrid.columns.getColumn(name); if (col) { col.format = format; } } function formatCellRange(cellRange) { let rng; rng = '(' + cellRange.row + ';' + cellRange.col + ')'; if (!cellRange.isSingleCell) { rng += '-(' + cellRange.row2 + ';' + cellRange.col2 + ')'; } return rng; } function currentItemChanged() { let curr = wjCore.format('{current:n0} / {count:n0}', { current: theGrid.collectionView.currentPosition + 1, count: theGrid.collectionView.items.length }); document.querySelector('#inputCurrent').value = curr; if (theGrid.collectionView.currentPosition === 0) { document.querySelector('#first').setAttribute('disabled', 'true'); document.querySelector('#previous').setAttribute('disabled', 'true'); } else { document.querySelector('#first').removeAttribute('disabled'); document.querySelector('#previous').removeAttribute('disabled'); } if (theGrid.collectionView.currentPosition === theGrid.collectionView.items.length - 1) { document.querySelector('#last').setAttribute('disabled', 'true'); document.querySelector('#next').setAttribute('disabled', 'true'); } else { document.querySelector('#last').removeAttribute('disabled'); document.querySelector('#next').removeAttribute('disabled'); } } function filterFunction(item) { let f = document.querySelector('#filter').value; if (f && item) { // split string into terms to enable multi-field searches such as 'us gadget red' let terms = f.toUpperCase().split(' '); // look for any term in any string field for (let i = 0; i < terms.length; i++) { let termFound = false; for (let key in item) { let value = item[key]; if (wjCore.isString(value) && value.toUpperCase().indexOf(terms[i]) > -1) { termFound = true; break; } } // fail if any of the terms is not found if (!termFound) { return false; } } } // include item in view return true; } /*function loadCulture(culture) { // get culture url var url = 'https://cdn.grapecity.com/wijmo/5.latest/controls/cultures/wijmo.culture.' + culture + '.min.js'; // apply new culture to page var scripts = document.getElementsByTagName('script'), script; for (var i = 0; i < scripts.length; i++) { script = scripts[i]; if (script.src.indexOf('/cultures/wijmo.culture.') > -1) { script.parentElement.removeChild(script); break; } } script = document.createElement('script'); script.onload = updateControls(); script.src = url; document.head.appendChild(script); } function updateControls() { wjCore.Control.invalidateAll(); }*/ } <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity Wijmo FlexGrid Overview</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app'); </script> </head> <body> <div class="container-fluid"> <div> <!-- search box --> <div class="row"> <div class="col-md-6 col-xs-4"> <input id="filter" type="text" class="form-control app-pad" placeholder="Filter" /> </div> <div class="col-md-6 col-xs-8"> <div class="pull-right wj-control wj-content wj-pager"> <div class="wj-input-group"> <span class="wj-input-group-btn"> <button id="first" class="wj-btn wj-btn-default" type="button"> <span class="wj-glyph-left" style="margin-right:-4px"></span> <span class="wj-glyph-left"></span> </button> </span> <span class="wj-input-group-btn"> <button id="previous" class="wj-btn wj-btn-default" type="button"> <span class="wj-glyph-left"></span> </button> </span> <input id="inputCurrent" type="text" class="wj-form-control" disabled> <span class="wj-input-group-btn"> <button id="next" class="wj-btn wj-btn-default" type="button"> <span class="wj-glyph-right"></span> </button> </span> <span class="wj-input-group-btn"> <button id="last" class="wj-btn wj-btn-default" type="button"> <span class="wj-glyph-right"></span> <span class="wj-glyph-right" style="margin-left:-4px"></span> </button> </span> </div> </div> </div> </div> <!-- the grid --> <div id="theGrid"> </div> </div> <!-- commands --> <div class="well"> <div class="grid-sort-group"> <!-- current selection --> <p>Selection: <b><span id="cellRange"></span></b></p> <!-- data size --> <div id="itemCountMenu"></div> <!-- allow add new --> <div id="allowAddNewMenu"></div> <!-- selection mode --> <div id="selectionModeMenu"></div> <!-- headers visibility --> <div id="headersVisibilityMenu"></div> <!-- highlight headers --> <div id="showSelectedHeadersMenu"></div> <!-- show marquee --> <div id="showMarqueeMenu"></div> <!-- data maps --> <div id="dataMapsMenu"></div> <!-- formatting --> <div id="formattingMenu"></div> <!-- culture --> <!-- <div id="cultureMenu"></div> --> <br /> <br /> <!-- testing the object model --> <button id="toggleColumnVisibility" class="btn btn-default"> Show/Hide Column </button> <button id="changeColumnSize" class="btn btn-default"> Resize Column </button> <button id="toggleRowVisibility" class="btn btn-default"> Show/Hide Row </button> <button id="changeRowSize" class="btn btn-default"> Resize Row </button> <button id="changeDefaultRowSize" class="btn btn-default"> Default Row Size </button> <button id="changeScrollPosition" class="btn btn-default"> Scroll Position </button> </div> </div> </div> </body> </html> import { CollectionView } from '@grapecity/wijmo'; let countries = ['US', 'Germany', 'UK', 'Japan', 'Italy', 'Greece']; let products = ['Widget', 'Gadget', 'Doohickey']; let colors = ['Black', 'White', 'Red', 'Green', 'Blue']; // generate some random data export function getData(count, currentChangedHdl) { let data = []; let dt = new Date(); // add count items for (let i = 0; i < count; i++) { // constants used to create data items let date = new Date(dt.getFullYear(), i % 12, 25, i % 24, i % 60, i % 60), countryId = Math.floor(Math.random() * countries.length), productId = Math.floor(Math.random() * products.length), colorId = Math.floor(Math.random() * colors.length); // create the item let item = { id: i, start: date, end: date, country: countries[countryId], product: products[productId], color: colors[colorId], countryId: countryId, productId: productId, colorId: colorId, amount: Math.random() * 10000 - 5000, amount2: Math.random() * 10000 - 5000, discount: Math.random() / 4, active: i % 4 == 0, }; // add an array (should not auto-bind) item.sales = []; for (var j = 0; j < 12; j++) { item.sales.push(50 + 20 * (Math.random() - .5) + j); } // add an object (should not auto-bind) item.someObject = { name: i, value: i }; // add the item to the list data.push(item); } // return a CollectionView so multiple controls bound to this source // will be updated automatically (TFS 145538) let cv = new CollectionView(data); if (currentChangedHdl) { cv.currentChanged.addHandler(currentChangedHdl); } return cv; } // get possible values for each field export function getCountries() { return countries; } export function getProducts() { return products; } export function getColors() { return colors; } .wj-flexgrid { height: 400px; margin: 6px 0; } .grid-sort-group .wj-menu, .grid-sort-group .btn { margin: 2px 4px 2px 0; } import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './styles.css'; // import { Component, Inject, enableProdMode, NgModule, ViewChild } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import * as wjcCore from '@grapecity/wijmo'; import * as wjcGrid from '@grapecity/wijmo.grid'; import { WjGridModule } from '@grapecity/wijmo.angular2.grid'; import { WjInputModule } from '@grapecity/wijmo.angular2.input'; import { AppPipesModule } from './app.pipe'; import { DataService } from './app.data'; // @Component({ selector: 'app-component', templateUrl: 'src/app.component.html' }) export class AppComponent { private _itemCount = 500; private _culture = 'en'; private _dataMaps = true; private _formatting = true; private _filter = ''; private _toFilter: any; private _thisFilterFunction: wjcCore.IPredicate; private _groupBy = ''; private _pageSize = 0; protected dataSvc: DataService; data: any[]; // references FlexGrid named 'flex' in the view @ViewChild('flex') flex: wjcGrid.FlexGrid; // DataSvc will be passed by derived classes constructor( @Inject(DataService) dataSvc: DataService) { this.dataSvc = dataSvc; this._thisFilterFunction = this._filterFunction.bind(this); this.data = dataSvc.getData(this.itemCount); } get itemCount(): number { return this._itemCount; } set itemCount(value: number) { if (this._itemCount != value) { this._itemCount = value; this.data = this.dataSvc.getData(this.itemCount); this.groupBy = ''; } } get dataMaps(): boolean { return this._dataMaps; } set dataMaps(value: boolean) { if (this._dataMaps != value) { this._dataMaps = value; this._updateDataMaps(); } } get formatting(): boolean { return this._formatting; } set formatting(value: boolean) { if (this._formatting != value) { this._formatting = value; this._updateFormatting(); } } get culture(): string { return this._culture; } set culture(value: string) { if (this._culture != value) { this._culture = value; this._loadCultureInfo(); } } get filter(): string { return this._filter; } set filter(value: string) { if (this._filter != value) { this._filter = value; this._applyFilter(); } } get groupBy(): string { return this._groupBy; } set groupBy(value: string) { if (this._groupBy != value) { this._groupBy = value; this._applyGroupBy(); } } get pageSize(): number { return this._pageSize; } set pageSize(value: number) { if (this._pageSize != value) { this._pageSize = value; if (this.flex) { (<wjcCore.IPagedCollectionView>this.flex.collectionView).pageSize = value; } } } ngAfterViewInit() { if (this.flex) { this.updateDataMapSettings(); } } // update data maps, formatting, paging now and when the itemsSource changes itemsSourceChangedHandler() { var flex = this.flex; if (!flex) { return; } // make columns 25% wider (for readability and to show how) for (var i = 0; i < flex.columns.length; i++) { flex.columns[i].width = flex.columns[i].renderSize * 1.25; } // update data maps and formatting this.updateDataMapSettings(); // set page size on the grid's internal collectionView if (flex.collectionView && this.pageSize) { (<wjcCore.IPagedCollectionView>flex.collectionView).pageSize = this.pageSize; } }; updateDataMapSettings() { this._updateDataMaps(); this._updateFormatting(); } toggleColumnVisibility() { var flex = this.flex; var col = flex.columns[0]; col.visible = !col.visible; }; changeColumnSize() { var flex = this.flex; var col = flex.columns[0]; col.visible = true; col.width = col.width < 0 ? 60 : -1; col = flex.rowHeaders.columns[0]; col.width = col.width < 0 ? 40 : -1; }; toggleRowVisibility() { var flex = this.flex; var row = flex.rows[0]; row.visible = !row.visible; }; changeRowSize() { var flex = this.flex; var row = flex.rows[0]; row.visible = true; row.height = row.height < 0 ? 80 : -1; row = flex.columnHeaders.rows[0]; row.height = row.height < 0 ? 80 : -1; }; changeDefaultRowSize() { var flex = this.flex; flex.rows.defaultSize = flex.rows.defaultSize == 28 ? 65 : 28; }; changeScrollPosition() { var flex = this.flex; if (flex.scrollPosition.y == 0) { var sz = flex.scrollSize; flex.scrollPosition = new wjcCore.Point(-sz.width / 2, -sz.height / 2); } else { flex.scrollPosition = new wjcCore.Point(0, 0); } }; // apply/remove data maps private _updateDataMaps() { var flex = this.flex; if (flex) { var colCountry = flex.columns.getColumn('countryId'); var colProduct = flex.columns.getColumn('productId'); var colColor = flex.columns.getColumn('colorId'); if (colCountry && colProduct && colColor) { if (this.dataMaps == true) { colCountry.showDropDown = true; // show drop-down for countries colProduct.showDropDown = false; // don't show it for products colColor.showDropDown = false; // or colors (just to show how) colCountry.dataMap = this._buildDataMap(this.dataSvc.getCountries()); colProduct.dataMap = this._buildDataMap(this.dataSvc.getProducts()); colColor.dataMap = this._buildDataMap(this.dataSvc.getColors()); } else { colCountry.dataMap = null; colProduct.dataMap = null; colColor.dataMap = null; } } } } // build a data map from a string array using the indices as keys private _buildDataMap(items: any[]): wjcGrid.DataMap { var map = []; for (var i = 0; i < items.length; i++) { map.push({ key: i, value: items[i] }); } return new wjcGrid.DataMap(map, 'key', 'value'); } // apply/remove column formatting private _updateFormatting() { var flex = this.flex; if (flex) { var fmt = this.formatting; this._setColumnFormat('amount', fmt ? 'c' : null); this._setColumnFormat('amount2', fmt ? 'c' : null); this._setColumnFormat('discount', fmt ? 'p0' : null); this._setColumnFormat('start', fmt ? 'MMM d yy' : null); this._setColumnFormat('end', fmt ? 'HH:mm' : null); } } private _setColumnFormat(name: string, format: string) { var col = this.flex.columns.getColumn(name); if (col) { col.format = format; } } private _loadCultureInfo() { wjcCore.httpRequest('bin/Devel/sources/cultures/wijmo.culture.' + this.culture + '.js', { dataType: 'script', success: (xhr: XMLHttpRequest) => { eval(xhr.response); wjcCore.Control.invalidateAll(); } }); } // ICollectionView filter function private _filterFunction(item: any) { var f = this.filter; if (f && item) { // split string into terms to enable multi-field searches such as 'us gadget red' var terms = f.toUpperCase().split(' '); // look for any term in any string field for (var i = 0; i < terms.length; i++) { var termFound = false; for (var key in item) { var value = item[key]; if (wjcCore.isString(value) && value.toUpperCase().indexOf(terms[i]) > -1) { termFound = true; break; } } // fail if any of the terms is not found if (!termFound) { return false; } } } // include item in view return true; } // apply filter (applied on a 500 ms timeOut) protected _applyFilter() { if (this._toFilter) { clearTimeout(this._toFilter); } var self = this; this._toFilter = setTimeout(function () { self._toFilter = null; if (self.flex) { var cv = self.flex.collectionView; if (cv) { if (cv.filter != self._thisFilterFunction) { cv.filter = self._thisFilterFunction; } else { cv.refresh(); } } } }, 500); } private _applyGroupBy() { if (this.flex) { // get the collection view, start update var cv = this.flex.collectionView; cv.beginUpdate(); // clear existing groups cv.groupDescriptions.clear(); // add new groups var groupNames = this.groupBy.split('/'), groupDesc; for (var i = 0; i < groupNames.length; i++) { var propName = groupNames[i].toLowerCase(); if (propName == 'amount') { // group amounts in ranges // (could use the mapping function to group countries into continents, // names into initials, etc) groupDesc = new wjcCore.PropertyGroupDescription(propName, function (item:any, prop: string) { var value = item[prop]; if (value > 1000) return 'Large Amounts'; if (value > 100) return 'Medium Amounts'; if (value > 0) return 'Small Amounts'; return 'Negative'; }); cv.groupDescriptions.push(groupDesc); } else if (propName) { // group other properties by their specific values groupDesc = new wjcCore.PropertyGroupDescription(propName); cv.groupDescriptions.push(groupDesc); } } // done updating cv.endUpdate(); } } } // @NgModule({ imports: [WjInputModule, WjGridModule, AppPipesModule, BrowserModule, FormsModule], declarations: [AppComponent], providers: [DataService], bootstrap: [AppComponent] }) export class AppModule { } // enableProdMode(); // Bootstrap application with hash style navigation and global services. platformBrowserDynamic().bootstrapModule(AppModule); <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity Wijmo FlexGrid Overview</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- Polyfills --> <script src="node_modules/core-js/client/shim.min.js"></script> <script src="node_modules/zone.js/dist/zone.min.js"></script> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.js"></script> <script src="systemjs.config.js"></script> <script> // workaround to load 'rxjs/operators' from the rxjs bundle System.import('rxjs').then(function (m) { System.set(SystemJS.resolveSync('rxjs/operators'), System.newModule(m.operators)); System.import('./src/app.component'); }); </script> </head> <body> <app-component></app-component> </body> </html> <div class="container-fluid"> <!-- search box --> <div class="row"> <div class="col-md-6 col-xs-4"> <input type="text" class="form-control app-pad" placeholder="Filter" [(ngModel)]="filter" /> </div> <div class="col-md-6 col-xs-8"> <wj-collection-view-navigator [cv]="flex.collectionView" class="pull-right"> </wj-collection-view-navigator> </div> </div> <!-- the grid --> <wj-flex-grid #flex class="grid" [allowResizing]="'Both'" [itemsSource]="data" [allowMerging]="'All'" [stickyHeaders]="true" (itemsSourceChanged)="itemsSourceChangedHandler()"> </wj-flex-grid> <!-- commands --> <div class="well"> <div class="grid-sort-group"> <!-- current selection --> <p>Selection: <b>{{flex.selection | cellRange}}</b></p> <!-- data size --> <wj-menu [(value)]="itemCount" [header]="'Items'"> <wj-menu-item [value]="5">5</wj-menu-item> <wj-menu-item [value]="50">50</wj-menu-item> <wj-menu-item [value]="500">500</wj-menu-item> <wj-menu-item [value]="5000">5,000</wj-menu-item> <wj-menu-item [value]="50000">50,000</wj-menu-item> <wj-menu-item [value]="100000">100,000</wj-menu-item> <wj-menu-item [value]="500000">500,000</wj-menu-item> <wj-menu-item [value]="1000000">1,000,000</wj-menu-item> </wj-menu> <!-- allow add new --> <wj-menu [(value)]="flex.allowAddNew" [header]="'Allow Add'"> <wj-menu-item [value]="true">True</wj-menu-item> <wj-menu-item [value]="false">False</wj-menu-item> </wj-menu> <!-- selection mode --> <wj-menu [(value)]="flex.selectionMode" [header]="'Selection'"> <wj-menu-item [value]="0">None</wj-menu-item> <wj-menu-item [value]="1">Cell</wj-menu-item> <wj-menu-item [value]="2">CellRange</wj-menu-item> <wj-menu-item [value]="3">Row</wj-menu-item> <wj-menu-item [value]="4">RowRange</wj-menu-item> <wj-menu-item [value]="5">ListBox</wj-menu-item> </wj-menu> <!-- headers visibility --> <wj-menu [(value)]="flex.headersVisibility" [header]="'Headers Visibility'"> <wj-menu-item [value]="0">None</wj-menu-item> <wj-menu-item [value]="1">Column</wj-menu-item> <wj-menu-item [value]="2">Row</wj-menu-item> <wj-menu-item [value]="3">All</wj-menu-item> </wj-menu> <!-- highlight headers --> <wj-menu [(value)]="flex.showSelectedHeaders" [header]="'Show Selected Headers'"> <wj-menu-item [value]="0">None</wj-menu-item> <wj-menu-item [value]="1">Column</wj-menu-item> <wj-menu-item [value]="2">Row</wj-menu-item> <wj-menu-item [value]="3">All</wj-menu-item> </wj-menu> <!-- show marquee --> <wj-menu [(value)]="flex.showMarquee" [header]="'Show Marquee'"> <wj-menu-item [value]="true">Yes</wj-menu-item> <wj-menu-item [value]="false">No</wj-menu-item> </wj-menu> <!-- data maps --> <wj-menu [(value)]="dataMaps" [header]="'Data Maps'"> <wj-menu-item [value]="true">On</wj-menu-item> <wj-menu-item [value]="false">Off</wj-menu-item> </wj-menu> <!-- formatting --> <wj-menu [(value)]="formatting" [header]="'Formatting'"> <wj-menu-item [value]="true">On</wj-menu-item> <wj-menu-item [value]="false">Off</wj-menu-item> </wj-menu> <!-- culture --> <!-- <wj-menu [(value)]="culture" [header]="'Culture'"> <wj-menu-item [value]="'en'">English</wj-menu-item> <wj-menu-item [value]="'de'">German</wj-menu-item> <wj-menu-item [value]="'it'">Italian</wj-menu-item> <wj-menu-item [value]="'fr'">French</wj-menu-item> <wj-menu-item [value]="'pt'">Portuguese</wj-menu-item> <wj-menu-item [value]="'ru'">Russian</wj-menu-item> <wj-menu-item [value]="'ja'">Japanese</wj-menu-item> <wj-menu-item [value]="'ko'">Korean</wj-menu-item> </wj-menu> --> <br /> <br /> <!-- testing the object model --> <button class="btn btn-default" (click)="toggleColumnVisibility()"> Show/Hide Column </button> <button class="btn btn-default" (click)="changeColumnSize()"> Resize Column </button> <button class="btn btn-default" (click)="toggleRowVisibility()"> Show/Hide Row </button> <button class="btn btn-default" (click)="changeRowSize()"> Resize Row </button> <button class="btn btn-default" (click)="changeDefaultRowSize()"> Default Row Size </button> <button class="btn btn-default" (click)="changeScrollPosition()"> Scroll Position </button> </div> </div> </div> import { Injectable } from '@angular/core'; @Injectable() export class DataService { // data used to generate random items private _products = ['Widget', 'Gadget', 'Doohickey']; private _colors = ['Black', 'White', 'Red', 'Green', 'Blue']; private _someCountries = ['US', 'Germany', 'UK', 'Japan', 'Italy', 'Greece']; getCountries(): string[] { return this._someCountries; } getProducts(): string[] { return this._products; } getColors(): string[] { return this._colors; } // get matches for a search term getData(count: number): any[] { var data = []; var dt = new Date(); // add count items for (var i = 0; i < count; i++) { // constants used to create data items var date = new Date(dt.getFullYear(), i % 12, 25, i % 24, i % 60, i % 60), countryId = Math.floor(Math.random() * this._someCountries.length), productId = Math.floor(Math.random() * this._products.length), colorId = Math.floor(Math.random() * this._colors.length); // create the item var item = { id: i, start: date, end: new Date(date.getTime() + Math.random() * 30 * (24 * 60 * 60 * 1000)), country: this._someCountries[countryId], product: this._products[productId], color: this._colors[colorId], countryId: countryId, productId: productId, colorId: colorId, amount: Math.random() * 10000 - 5000, amount2: Math.random() * 10000 - 5000, discount: Math.random() / 4, active: i % 4 == 0 }; // add the item to the list data.push(item); } return data; } } .wj-flexgrid { height: 400px; margin: 6px 0; } .grid-sort-group .wj-menu, .grid-sort-group .btn { margin: 2px 2px 2px 0; } <template> <div class="container-fluid"> <!-- search box --> <div class="row"> <div class="col-md-6 col-xs-4"> <input type="text" class="form-control app-pad" placeholder="Filter" v-model="filter" > </div> <div class="col-md-6 col-xs-8"> <div class="pull-right wj-control wj-content wj-pager"> <div class="wj-input-group"> <span class="wj-input-group-btn"> <button id="first" class="wj-btn wj-btn-default" type="button"> <span class="wj-glyph-left" style="margin-right:-4px"></span> <span class="wj-glyph-left"></span> </button> </span> <span class="wj-input-group-btn"> <button id="previous" class="wj-btn wj-btn-default" type="button"> <span class="wj-glyph-left"></span> </button> </span> <input id="inputCurrent" type="text" class="wj-form-control" disabled> <span class="wj-input-group-btn"> <button id="next" class="wj-btn wj-btn-default" type="button"> <span class="wj-glyph-right"></span> </button> </span> <span class="wj-input-group-btn"> <button id="last" class="wj-btn wj-btn-default" type="button"> <span class="wj-glyph-right"></span> <span class="wj-glyph-right" style="margin-left:-4px"></span> </button> </span> </div> </div> </div> </div> <!-- the grid --> <wj-flex-grid :initialized="initialized" class="grid" :itemsSourceChanged="itemsSourceChangedHandler" :allowResizing="'Both'" :allowMerging="'All'" :stickyHeaders="true" ></wj-flex-grid> <!-- commands --> <div class="well"> <div class="grid-sort-group"> <!-- current selection --> <p> Selection: <b>{{selection}}</b> </p> <!-- data size --> <wj-menu :header="'Items'" :itemsSource="itemCountSource" :displayMemberPath="'header'" :selectedValuePath="'value'" :selectedIndexChanged="selectedIndexChanged.bind(this,'itemCount')" :initialized="initMenu.bind(this,'itemCount')" ></wj-menu> <!-- allow add new --> <wj-menu :header="'Allow Add'" :itemsSource="addNewRowSource" :displayMemberPath="'header'" :selectedValuePath="'value'" :selectedIndexChanged="selectedIndexChanged.bind(this,'allowAddNew')" :initialized="initMenu.bind(this,'allowAddNew')" ></wj-menu> <!-- selection mode --> <wj-menu :header="'Selection'" :itemsSource="selectionModeSource" :displayMemberPath="'header'" :selectedValuePath="'value'" :selectedIndexChanged="selectedIndexChanged.bind(this,'selectionMode')" :initialized="initMenu.bind(this,'selectionMode')" ></wj-menu> <!-- headers visibility --> <wj-menu :header="'Headers Visibility'" :itemsSource="headersVisibilitySource" :displayMemberPath="'header'" :selectedValuePath="'value'" :selectedIndexChanged="selectedIndexChanged.bind(this,'headersVisibility')" :initialized="initMenu.bind(this,'headersVisibility')" ></wj-menu> <!-- highlight headers --> <wj-menu :header="'Show Selected Headers'" :itemsSource="howSelectedHeadersSource" :displayMemberPath="'header'" :selectedValuePath="'value'" :selectedIndexChanged="selectedIndexChanged.bind(this,'showSelectedHeaders')" :initialized="initMenu.bind(this,'showSelectedHeaders')" ></wj-menu> <!-- show marquee --> <wj-menu :header="'Show Marquee'" :itemsSource="showMarqueeSource" :displayMemberPath="'header'" :selectedValuePath="'value'" :selectedIndexChanged="selectedIndexChanged.bind(this,'showMarquee')" :initialized="initMenu.bind(this,'showMarquee')" ></wj-menu> <!-- data maps --> <wj-menu :header="'Data Maps'" :itemsSource="dataMapsSource" :displayMemberPath="'header'" :selectedValuePath="'value'" :selectedIndexChanged="selectedIndexChanged.bind(this,'dataMaps')" :initialized="initMenu.bind(this,'dataMaps')" ></wj-menu> <!-- formatting --> <wj-menu :header="'Formatting'" :itemsSource="formattingSource" :displayMemberPath="'header'" :selectedValuePath="'value'" :selectedIndexChanged="selectedIndexChanged.bind(this,'formatting')" :initialized="initMenu.bind(this,'formatting')" ></wj-menu> <br> <br> <!-- testing the object model --> <button class="btn btn-default" @click="toggleColumnVisibility()">Show/Hide Column</button> <button class="btn btn-default" @click="changeColumnSize()">Resize Column</button> <button class="btn btn-default" @click="toggleRowVisibility()">Show/Hide Row</button> <button class="btn btn-default" @click="changeRowSize()">Resize Row</button> <button class="btn btn-default" @click="changeDefaultRowSize()">Default Row Size</button> <button class="btn btn-default" @click="changeScrollPosition()">Scroll Position</button> </div> </div> </div> </template> <script> import "@grapecity/wijmo.styles/wijmo.css"; import "bootstrap.css"; import * as wjcCore from "@grapecity/wijmo"; import * as wjcGrid from "@grapecity/wijmo.grid"; import Vue from "vue"; import { getCountries, getProducts, getColors, getData } from "./data"; import "@grapecity/wijmo.vue2.grid"; import "@grapecity/wijmo.vue2.input"; new Vue({ el: "#app", data: { itemCountField: 500, cultureField: "en", dataMapsField: true, formattingField: true, filterField: "", toFilterField: null, thisFilterFunctionField: null, groupByField: "", pageSizeField: 0, collectionViewField: null, selectionField: null, allowAddNewField: null, selectionModeField: null, headersVisibilityField: null, showSelectedHeadersField: null, showMarqueeField: null, itemCountSource: [ { header: "5", value: 5 }, { header: "50", value: 50 }, { header: "500", value: 500 }, { header: "5,000", value: 5000 }, { header: "50,000", value: 50000 }, { header: "100,000", value: 100000 }, { header: "500,000", value: 500000 }, { header: "1,000,000", value: 1000000 } ], addNewRowSource: [ { header: "Yes", value: true }, { header: "No", value: false } ], selectionModeSource: [ { header: "None", value: wjcGrid.SelectionMode.None }, { header: "Cell", value: wjcGrid.SelectionMode.Cell }, { header: "CellRange", value: wjcGrid.SelectionMode.CellRange }, { header: "Row", value: wjcGrid.SelectionMode.Row }, { header: "RowRange", value: wjcGrid.SelectionMode.RowRange }, { header: "ListBox", value: wjcGrid.SelectionMode.ListBox } ], headersVisibilitySource: [ { header: "None", value: wjcGrid.HeadersVisibility.None }, { header: "Column", value: wjcGrid.HeadersVisibility.Column }, { header: "Row", value: wjcGrid.HeadersVisibility.Row }, { header: "All", value: wjcGrid.HeadersVisibility.All } ], howSelectedHeadersSource: [ { header: "None", value: wjcGrid.HeadersVisibility.None }, { header: "Column", value: wjcGrid.HeadersVisibility.Column }, { header: "Row", value: wjcGrid.HeadersVisibility.Row }, { header: "All", value: wjcGrid.HeadersVisibility.All } ], showMarqueeSource: [ { header: "On", value: true }, { header: "Off", value: false } ], dataMapsSource: [ { header: "On", value: true }, { header: "Off", value: false } ], formattingSource: [ { header: "On", value: true }, { header: "Off", value: false } ] }, methods: { initialized: function(flex) { this.flex = flex; this.collectionView = this.flex.collectionView; this.selection = this.flex.selection; this.allowAddNew = this.flex.allowAddNew; this.selectionMode = this.flex.selectionMode; this.headersVisibility = this.flex.headersVisibility; this.showSelectedHeaders = this.flex.showSelectedHeaders; this.showMarquee = this.flex.showMarquee; this.flex.select(new wjcGrid.CellRange(0, 0)); this.flex.selectionChanged.addHandler((s, e) => { this.selection = e.range; }); this.flex.itemsSource = getData(this.itemCount); }, formatMenuHeader: function(menu) { let index = menu.header.indexOf(":"); if (index !== -1) { menu.header = menu.header.substring(0, menu.header.indexOf(":")) + wjcCore.format(": <b>{header}</b>", menu.selectedItem); } else { menu.header = menu.header + wjcCore.format(": <b>{header}</b>", menu.selectedItem); } }, // update data maps, formatting, paging now and when the itemsSource changes itemsSourceChangedHandler: function() { var flex = this.flex; if (!flex) { return; } // make columns 25% wider (for readability and to show how) for (var i = 0; i < flex.columns.length; i++) { flex.columns[i].width = flex.columns[i].renderSize * 1.25; } // update data maps and formatting this.updateDataMapSettings(); // set page size on the grid's internal collectionView if (flex.collectionView && this.pageSize) { flex.collectionView.pageSize = this.pageSize; } }, updateDataMapSettings: function() { this._updateDataMaps(); this._updateFormatting(); }, toggleColumnVisibility: function() { var flex = this.flex; var col = flex.columns[0]; col.visible = !col.visible; }, changeColumnSize: function() { var flex = this.flex; var col = flex.columns[0]; col.visible = true; col.width = col.width < 0 ? 60 : -1; col = flex.rowHeaders.columns[0]; col.width = col.width < 0 ? 40 : -1; }, toggleRowVisibility: function() { var flex = this.flex; var row = flex.rows[0]; row.visible = !row.visible; }, changeRowSize: function() { var flex = this.flex; var row = flex.rows[0]; row.visible = true; row.height = row.height < 0 ? 80 : -1; row = flex.columnHeaders.rows[0]; row.height = row.height < 0 ? 80 : -1; }, changeDefaultRowSize: function() { var flex = this.flex; flex.rows.defaultSize = flex.rows.defaultSize == 28 ? 65 : 28; }, changeScrollPosition: function() { var flex = this.flex; if (flex.scrollPosition.y == 0) { var sz = flex.scrollSize; flex.scrollPosition = new wjcCore.Point( -sz.width / 2, -sz.height / 2 ); } else { flex.scrollPosition = new wjcCore.Point(0, 0); } }, // apply/remove data maps _updateDataMaps: function() { var flex = this.flex; if (flex) { var colCountry = flex.columns.getColumn("countryId"); var colProduct = flex.columns.getColumn("productId"); var colColor = flex.columns.getColumn("colorId"); if (colCountry && colProduct && colColor) { if (this.dataMaps == true) { colCountry.showDropDown = true; // show drop-down for countries colProduct.showDropDown = false; // don't show it for products colColor.showDropDown = false; // or colors (just to show how) colCountry.dataMap = this._buildDataMap(getCountries()); colProduct.dataMap = this._buildDataMap(getProducts()); colColor.dataMap = this._buildDataMap(getColors()); } else { colCountry.dataMap = null; colProduct.dataMap = null; colColor.dataMap = null; } } } }, // build a data map from a string array using the indices as keys _buildDataMap: function(items) { var map = []; for (var i = 0; i < items.length; i++) { map.push({ key: i, value: items[i] }); } return new wjcGrid.DataMap(map, "key", "value"); }, // apply/remove column formatting _updateFormatting: function() { var flex = this.flex; if (flex) { var fmt = this.formatting; this._setColumnFormat("amount", fmt ? "c" : null); this._setColumnFormat("amount2", fmt ? "c" : null); this._setColumnFormat("discount", fmt ? "p0" : null); this._setColumnFormat("start", fmt ? "MMM d yy" : null); this._setColumnFormat("end", fmt ? "HH:mm" : null); } }, _setColumnFormat: function(name, format) { var col = this.flex.columns.getColumn(name); if (col) { col.format = format; } }, _loadCultureInfo: function() { wjcCore.httpRequest( "bin/Devel/sources/cultures/wijmo.culture." + this.culture + ".js", { dataType: "script", success: xhr => { eval(xhr.response); wjcCore.Control.invalidateAll(); } } ); }, // ICollectionView filter function filterFieldFunction: function(item) { var f = this.filter; if (f && item) { // split string into terms to enable multi-field searches such as 'us gadget red' var terms = f.toUpperCase().split(" "); // look for any term in any string field for (var i = 0; i < terms.length; i++) { var termFound = false; for (var key in item) { var value = item[key]; if ( wjcCore.isString(value) && value.toUpperCase().indexOf(terms[i]) > -1 ) { termFound = true; break; } } // fail if any of the terms is not found if (!termFound) { return false; } } } // include item in view return true; }, // apply filter (applied on a 500 ms timeOut) _applyFilter: function() { if (this.toFilterField) { clearTimeout(this.toFilterField); } var self = this; this.toFilterField = setTimeout(function() { self.toFilterField = null; if (self.flex) { var cv = self.flex.collectionView; if (cv) { if (cv.filter != self.filterFieldFunction) { cv.filter = self.filterFieldFunction; } else { cv.refresh(); } } } }, 500); }, _applyGroupBy: function() { if (this.flex) { // get the collection view, start update var cv = this.flex.collectionView; cv.beginUpdate(); // clear existing groups cv.groupDescriptions.clear(); // add new groups var groupNames = this.groupBy.split("/"), groupDesc; for (var i = 0; i < groupNames.length; i++) { var propName = groupNames[i].toLowerCase(); if (propName == "amount") { // group amounts in ranges // (could use the mapping function to group countries into continents, // names into initials, etc) groupDesc = new wjcCore.PropertyGroupDescription( propName, function(item, prop) { var value = item[prop]; if (value > 1000) return "Large Amounts"; if (value > 100) return "Medium Amounts"; if (value > 0) return "Small Amounts"; return "Negative"; } ); cv.groupDescriptions.push(groupDesc); } else if (propName) { // group other properties by their specific values groupDesc = new wjcCore.PropertyGroupDescription( propName ); cv.groupDescriptions.push(groupDesc); } } // done updating cv.endUpdate(); } }, selectedIndexChanged: function(prop, s, e) { if (s.selectedIndex > -1) { this.formatMenuHeader(s); this[prop] = s.selectedValue; } }, initEvent: function() { document.querySelector("#first").addEventListener("click", () => { this.flex.collectionView.moveCurrentToFirst(); this.currentItemChanged(); }); document .querySelector("#previous") .addEventListener("click", () => { this.flex.collectionView.moveCurrentToPrevious(); this.currentItemChanged(); }); document.querySelector("#next").addEventListener("click", () => { this.flex.collectionView.moveCurrentToNext(); this.currentItemChanged(); }); document.querySelector("#last").addEventListener("click", () => { this.flex.collectionView.moveCurrentToLast(); this.currentItemChanged(); }); }, currentItemChanged: function() { let curr = wjcCore.format("{current:n0} / {count:n0}", { current: this.flex.collectionView.currentPosition + 1, count: this.flex.collectionView.items.length }); document.querySelector("#inputCurrent").value = curr; if (this.flex.collectionView.currentPosition === 0) { document .querySelector("#first") .setAttribute("disabled", "true"); document .querySelector("#previous") .setAttribute("disabled", "true"); } else { document.querySelector("#first").removeAttribute("disabled"); document.querySelector("#previous").removeAttribute("disabled"); } if ( this.flex.collectionView.currentPosition === this.flex.collectionView.items.length - 1 ) { document .querySelector("#last") .setAttribute("disabled", "true"); document .querySelector("#next") .setAttribute("disabled", "true"); } else { document.querySelector("#last").removeAttribute("disabled"); document.querySelector("#next").removeAttribute("disabled"); } }, initMenu: function(type, s) { this.formatMenuHeader(s); switch (type) { case "itemCount": s.selectedValue = this.itemCount; return; case "allowAddNew": s.selectedValue = this.allowAddNew; return; case "selectionMode": s.selectedValue = this.selectionMode; return; case "headersVisibility": s.selectedValue = this.headersVisibility; return; case "showSelectedHeaders": s.selectedValue = this.showSelectedHeaders; return; case "showMarquee": s.selectedValue = false; return; case "dataMaps": s.selectedValue = true; return; case "formatting": s.selectedValue = true; return; } }, filterFunction: function(item) { var f = this.filter; if (f && item) { // split string into terms to enable multi-field searches such as 'us gadget red' var terms = f.toUpperCase().split(" "); // look for any term in any string field for (var i = 0; i < terms.length; i++) { var termFound = false; for (var key in item) { var value = item[key]; if ( wjcCore.isString(value) && value.toUpperCase().indexOf(terms[i]) > -1 ) { termFound = true; break; } } // fail if any of the terms is not found if (!termFound) { return false; } } } // include item in view return true; } }, mounted: function() { this.initEvent(); this.thisFilterFunction = this.filterFieldFunction.bind(this); this.flex.itemsSouce = getData(this.itemCount); if (this.flex) { this.updateDataMapSettings(); } this.currentItemChanged(); }, computed: { collectionView: { get: function() { return this.collectionViewField; }, set: function(value) { this.collectionViewField = value; } }, selection: { get: function() { var value = this.selectionField; var rng = ""; if (value instanceof wjcGrid.CellRange) { rng = "(" + value.row + ";" + value.col + ")"; if (!value.isSingleCell) { rng += "-(" + value.row2 + ";" + value.col2 + ")"; } } return rng; }, set: function(value) { this.selectionField = value; } }, allowAddNew: { get: function() { return this.allowAddNewField; }, set: function(value) { this.allowAddNewField = value; if (this.flex) { this.flex.allowAddNew = value; } } }, selectionMode: { get: function() { return this.selectionModeField; }, set: function(value) { this.selectionModeField = value; if (this.flex) { this.flex.selectionMode = value; } } }, headersVisibility: { get: function() { return this.headersVisibilityField; }, set: function(value) { this.headersVisibilityField = value; if (this.flex) { this.flex.headersVisibility = value; } } }, showSelectedHeaders: { get: function() { return this.showSelectedHeadersField; }, set: function(value) { this.showSelectedHeadersField = value; if (this.flex) { this.flex.showSelectedHeaders = value; } } }, showMarquee: { get: function() { return this.showMarqueeField; }, set: function(value) { this.showMarqueeField = value; if (this.flex) { this.flex.showMarquee = value; } } }, itemCount: { get: function() { return this.itemCountField; }, set: function(value) { if (this.itemCountField != value) { this.itemCountField = value; this.flex.itemsSource = getData(this.itemCount); this.groupBy = ""; this.currentItemChanged(); } } }, dataMaps: { get: function() { return this.dataMapsField; }, set: function(value) { if (this.dataMapsField != value) { this.dataMapsField = value; this._updateDataMaps(); } } }, formatting: { get: function() { return this.formattingField; }, set: function(value) { if (this.formattingField != value) { this.formattingField = value; this._updateFormatting(); } } }, culture: { get: function() { return this.cultureField; }, set: function(value) { if (this.cultureField != value) { this.cultureField = value; this._loadCultureInfo(); } } }, filter: { get: function() { return this.filterField; }, set: function(value) { if (this.filterField != value) { this.filterField = value; this._applyFilter(); } } }, groupBy: { get: function() { return this.groupByField; }, set: function(value) { if (this.groupByField != value) { this.groupByField = value; this._applyGroupBy(); } } }, pageSize: { get: function() { return this.pageSizeField; }, set: function(value) { if (this.pageSizeField != value) { this.pageSizeField = value; if (this.flex) { this.flex.collectionView.pageSize = value; } } } } }, updated:function(s,e){ } }); </script> <style> .wj-flexgrid { height: 400px; margin: 6px 0; } .grid-sort-group .wj-menu, .grid-sort-group .btn { margin: 2px 2px 2px 0; } </style> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity Wijmo FlexGrid Overview</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app.vue'); </script> </head> <body> <div id="app"> </div> </body> </html> var _products = ['Widget', 'Gadget', 'Doohickey']; var _colors = ['Black', 'White', 'Red', 'Green', 'Blue']; var _someCountries = ['US', 'Germany', 'UK', 'Japan', 'Italy', 'Greece']; export function getCountries() { return _someCountries; } export function getProducts() { return _products; } export function getColors() { return _colors; } // get matches for a search term export function getData(count) { var data = []; var dt = new Date(); // add count items for (var i = 0; i < count; i++) { // constants used to create data items var date = new Date(dt.getFullYear(), i % 12, 25, i % 24, i % 60, i % 60), countryId = Math.floor(Math.random() * _someCountries.length), productId = Math.floor(Math.random() * _products.length), colorId = Math.floor(Math.random() * _colors.length); // create the item var item = { id: i, start: date, end: new Date(date.getTime() + Math.random() * 30 * (24 * 60 * 60 * 1000)), country: _someCountries[countryId], product: _products[productId], color: _colors[colorId], countryId: countryId, productId: productId, colorId: colorId, amount: Math.random() * 10000 - 5000, amount2: Math.random() * 10000 - 5000, discount: Math.random() / 4, active: i % 4 == 0 }; // add the item to the list data.push(item); } return data; } import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './app.css'; // import * as React from 'react'; import * as ReactDOM from 'react-dom'; import * as wijmo from '@grapecity/wijmo'; import * as grid from '@grapecity/wijmo.grid'; // import * as wjInput from '@grapecity/wijmo.react.input'; import * as wjGrid from '@grapecity/wijmo.react.grid'; import { Navigator } from './navigator'; import { getData, getCountries, getProducts, getColors } from './data'; // var MenuType; (function (MenuType) { MenuType[MenuType["allowAdd"] = 1] = "allowAdd"; MenuType[MenuType["dataMaps"] = 7] = "dataMaps"; MenuType[MenuType["formatting"] = 8] = "formatting"; MenuType[MenuType["headersVisibility"] = 2] = "headersVisibility"; MenuType[MenuType["itemsCount"] = 3] = "itemsCount"; MenuType[MenuType["selectionMode"] = 4] = "selectionMode"; MenuType[MenuType["showMarquee"] = 5] = "showMarquee"; MenuType[MenuType["showSelectedHeaders"] = 6] = "showSelectedHeaders"; })(MenuType || (MenuType = {})); // class App extends React.Component { // constructor(props) { super(props); this.Values = { headersVisibility: ['None', 'Column', 'Row', 'All'], itemsCount: [ { value: 5, text: '5' }, { value: 50, text: '50' }, { value: 500, text: '500' }, { value: 5000, text: '5,000' }, { value: 50000, text: '50,000' }, { value: 100000, text: '100,000' }, { value: 500000, text: '500,000' }, { value: 1000000, text: '1,000,000' } ], onOff: [ { value: true, text: 'On' }, { value: false, text: 'Off' } ], selectionMode: ['None', 'Cell', 'CellRange', 'Row', 'RowRange', 'ListBox'], yesNo: [ { value: true, text: 'Yes' }, { value: false, text: 'No' } ] }; // this._toFilter = null; this._itemsCount = 500; this.state = { allowAdd: false, dataMaps: true, filter: '', formatting: true, headersVisibility: 'All', selectionMode: 'CellRange', showMarquee: false, showSelectedHeaders: 'None', data: getData(this._itemsCount), selection: '' }; } // get allowAdd() { return this.state.allowAdd; } set allowAdd(value) { if (this.state.allowAdd !== value) { this.setState({ allowAdd: value }); } } // get dataMaps() { return this.state.dataMaps; } set dataMaps(value) { if (this.state.dataMaps !== value) { this.setState({ dataMaps: value }); this._updateDataMaps(); } } // get formatting() { return this.state.formatting; } set formatting(value) { if (this.state.formatting !== value) { this.setState({ formatting: value }); this._updateFormatting(); } } // get filter() { return this.state.filter; } set filter(value) { if (this.filter !== value) { this.setState({ filter: value }); this._applyFilter(); } } // get headersVisibility() { return this.state.headersVisibility; } set headersVisibility(value) { if (this.state.headersVisibility !== value) { this.setState({ headersVisibility: value }); } } // get itemsCount() { return this._itemsCount; } set itemsCount(value) { if (this._itemsCount !== value) { this._itemsCount = value; this.setState({ data: getData(value) }); } } // get selectionMode() { return this.state.selectionMode; } set selectionMode(value) { if (this.state.selectionMode !== value) { this.setState({ selectionMode: value }); } } // get showMarquee() { return this.state.showMarquee; } set showMarquee(value) { if (this.state.showMarquee !== value) { this.setState({ showMarquee: value }); } } // get showSelectedHeaders() { return this.state.showSelectedHeaders; } set showSelectedHeaders(value) { if (this.state.showSelectedHeaders !== value) { this.setState({ showSelectedHeaders: value }); } } // componentDidMount() { this._updateDataMapSettings(); } // render() { return <div className='container-fluid'> <div className='row'> <div className='col-md-6 col-xs-4'> <input type='text' className='form-control app-pad' placeholder='Filter' value={this.filter} onChange={this._filterChanged.bind(this)}/> </div> <div className='col-md-6 col-xs-8'> <Navigator view={this.state.data} className='pull-right'> </Navigator> </div> </div> <wjGrid.FlexGrid allowAddNew={this.allowAdd} allowMerging='All' allowResizing='Both' headersVisibility={this.headersVisibility} selectionMode={this.selectionMode} showMarquee={this.showMarquee} showSelectedHeaders={this.showSelectedHeaders} stickyHeaders={true} itemsSource={this.state.data} initialized={this._gridInitialized.bind(this)} itemsSourceChanged={this._gridItemsSourceChanged.bind(this)} selectionChanged={this._gridSelectionChanged.bind(this)}> </wjGrid.FlexGrid> <div className='well'> <div className='grid-sort-group form-group row'> <p>Selection: <b>{this.state.selection}</b></p> <wjInput.Menu header={'<b>Items:</b> ' + this._getText(this.Values.itemsCount, this._itemsCount)} selectedValuePath='value' displayMemberPath='text' selectedValue={this.itemsCount} itemsSource={this.Values.itemsCount} selectedIndexChanged={this._menuChanged.bind(this, MenuType.itemsCount)}> </wjInput.Menu> <wjInput.Menu header={'<b>Allow Add:</b> ' + this._getText(this.Values.yesNo, this.allowAdd)} selectedValuePath='value' displayMemberPath='text' selectedValue={this.allowAdd} itemsSource={this.Values.yesNo} selectedIndexChanged={this._menuChanged.bind(this, MenuType.allowAdd)}> </wjInput.Menu> <wjInput.Menu header={'<b>Selection:</b> ' + this.selectionMode} selectedValue={this.selectionMode} itemsSource={this.Values.selectionMode} selectedIndexChanged={this._menuChanged.bind(this, MenuType.selectionMode)}> </wjInput.Menu> <wjInput.Menu header={'<b>Headers Visibility:</b> ' + this.headersVisibility} selectedValue={this.headersVisibility} itemsSource={this.Values.headersVisibility} selectedIndexChanged={this._menuChanged.bind(this, MenuType.headersVisibility)}> </wjInput.Menu> <wjInput.Menu header={'<b>Show Selected Headers:</b> ' + this.showSelectedHeaders} selectedValue={this.showSelectedHeaders} itemsSource={this.Values.headersVisibility} selectedIndexChanged={this._menuChanged.bind(this, MenuType.showSelectedHeaders)}> </wjInput.Menu> <wjInput.Menu header={'<b>Show Marquee:</b> ' + this._getText(this.Values.yesNo, this.showMarquee)} selectedValuePath='value' displayMemberPath='text' selectedValue={this.showMarquee} itemsSource={this.Values.yesNo} selectedIndexChanged={this._menuChanged.bind(this, MenuType.showMarquee)}> </wjInput.Menu> <wjInput.Menu header={'<b>Data Maps:</b> ' + this._getText(this.Values.onOff, this.dataMaps)} selectedValuePath='value' displayMemberPath='text' selectedValue={this.dataMaps} itemsSource={this.Values.onOff} selectedIndexChanged={this._menuChanged.bind(this, MenuType.dataMaps)}> </wjInput.Menu> <wjInput.Menu header={'<b>Formatting:</b> ' + this._getText(this.Values.onOff, this.formatting)} selectedValuePath='value' displayMemberPath='text' selectedValue={this.formatting} itemsSource={this.Values.onOff} selectedIndexChanged={this._menuChanged.bind(this, MenuType.formatting)}> </wjInput.Menu> <br /> <br /> <button className='btn btn-default' onClick={this._toggleColumnVisibility.bind(this)}> Show/Hide Column </button> <button className='btn btn-default' onClick={this._changeColumnSize.bind(this)}> Resize Column </button> <button className='btn btn-default' onClick={this._toggleRowVisibility.bind(this)}> Show/Hide Row </button> <button className='btn btn-default' onClick={this._changeRowSize.bind(this)}> Resize Row </button> <button className='btn btn-default' onClick={this._changeDefaultRowSize.bind(this)}> Default Row Size </button> <button className='btn btn-default' onClick={this._changeScrollPosition.bind(this)}> Scroll Position </button> </div> </div> </div>; } // // apply filter (applied on a 500 ms timeOut) _applyFilter() { if (this._toFilter) { clearTimeout(this._toFilter); } // this._toFilter = setTimeout(() => { this._toFilter = null; if (this._grid) { let view = this._grid.collectionView; if (view) { if (!this.filter) { view.filter = null; } else { if (!view.filter) { view.filter = this._filterFunction.bind(this); } else { view.refresh(); } } } } }, 500); } // // ICollectionView filter function _filterFunction(item) { let f = this.filter; if (f && item) { // // split string into terms to enable multi-field searches such as 'us gadget red' let terms = f.toUpperCase().split(' '); // // look for any term in any string field for (let i = 0; i < terms.length; i++) { let termFound = false; for (let key in item) { let value = item[key]; if (wijmo.isString(value) && value.toUpperCase().indexOf(terms[i]) > -1) { termFound = true; break; } } // // fail if any of the terms is not found if (!termFound) { return false; } } } // // include item in view return true; } // _toggleColumnVisibility() { let col = this._grid.columns[0]; col.visible = !col.visible; } // _changeColumnSize() { let col = this._grid.columns[0]; col.visible = true; col.width = col.width < 0 ? 60 : -1; col = this._grid.rowHeaders.columns[0]; col.width = col.width < 0 ? 40 : -1; } // _toggleRowVisibility() { let row = this._grid.rows[0]; row.visible = !row.visible; } // _changeRowSize() { let row = this._grid.rows[0]; row.visible = true; row.height = row.height < 0 ? 80 : -1; row = this._grid.columnHeaders.rows[0]; row.height = row.height < 0 ? 80 : -1; } // _changeDefaultRowSize() { this._grid.rows.defaultSize = this._grid.rows.defaultSize == 28 ? 65 : 28; } // _changeScrollPosition() { let flex = this._grid; if (flex.scrollPosition.y == 0) { let sz = flex.scrollSize; flex.scrollPosition = new wijmo.Point(-sz.width / 2, -sz.height / 2); } else { flex.scrollPosition = new wijmo.Point(0, 0); } } // _gridInitialized(sender) { this._grid = sender; this.setState({ selection: this._cellRangeToString(sender.selection) }); } // _gridSelectionChanged(sender) { this.setState({ selection: this._cellRangeToString(sender.selection) }); } // _gridItemsSourceChanged(sender) { // make columns 25% wider (for readability and to show how) sender.columns.forEach((col) => col.width = col.renderSize * 1.25); // // update data maps and formatting this._updateDataMapSettings(); // // clear filter // this.filter = ''; } // _filterChanged(e) { this.filter = e.target.value; } // _menuChanged(type, menu) { if (menu.selectedIndex < 0) { return; } // switch (type) { case MenuType.itemsCount: this.itemsCount = menu.selectedValue; break; case MenuType.allowAdd: this.allowAdd = menu.selectedValue; break; case MenuType.dataMaps: this.dataMaps = menu.selectedValue; break; case MenuType.formatting: this.formatting = menu.selectedValue; break; case MenuType.headersVisibility: this.headersVisibility = menu.selectedValue; break; case MenuType.selectionMode: this.selectionMode = menu.selectedValue; break; case MenuType.showMarquee: this.showMarquee = menu.selectedValue; break; case MenuType.showSelectedHeaders: this.showSelectedHeaders = menu.selectedValue; break; } } // _getText(map, value) { return map.filter(val => val.value === value)[0].text; } // _cellRangeToString(value) { let rng = ''; // if (value instanceof grid.CellRange) { rng = `(${value.row};${value.col})`; if (!value.isSingleCell) { rng += `-(${value.row2};${value.col2})`; } } return rng; } // // apply/remove data maps _updateDataMaps() { if (!this._grid) { return; } // let country = this._grid.columns.getColumn('countryId'), product = this._grid.columns.getColumn('productId'), color = this._grid.columns.getColumn('colorId'); // if (country && product && color) { if (this.dataMaps == true) { country.showDropDown = true; // show drop-down for countries product.showDropDown = false; // don't show it for products color.showDropDown = false; // or colors (just to show how) country.dataMap = this._buildDataMap(getCountries()); product.dataMap = this._buildDataMap(getProducts()); color.dataMap = this._buildDataMap(getColors()); } else { country.dataMap = null; product.dataMap = null; color.dataMap = null; } } } // // build a data map from a string array using the indices as keys _buildDataMap(items) { let map = items.map((v, i) => ({ key: i, value: v })); return new grid.DataMap(map, 'key', 'value'); } // // apply/remove column formatting _updateFormatting() { if (!this._grid) { return; } // let fmt = this.formatting; this._setColumnFormat('amount', fmt ? 'c' : null); this._setColumnFormat('amount2', fmt ? 'c' : null); this._setColumnFormat('discount', fmt ? 'p0' : null); this._setColumnFormat('start', fmt ? 'MMM d yy' : null); this._setColumnFormat('end', fmt ? 'HH:mm' : null); } // _setColumnFormat(name, format) { let col = this._grid.columns.getColumn(name); if (col) { col.format = format; } } // _updateDataMapSettings() { this._updateDataMaps(); this._updateFormatting(); } } // ReactDOM.render(<App />, document.getElementById('app')); <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity Wijmo FlexGrid Overview</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app'); </script> </head> <body> <div id="app"></div> </body> </html> .wj-flexgrid { height: 400px; margin: 6px 0; } .grid-sort-group .wj-menu, .grid-sort-group .btn { margin: 2px 2px 2px 0; } import { CollectionView } from '@grapecity/wijmo'; // let countries = ['US', 'Germany', 'UK', 'Japan', 'Italy', 'Greece']; let products = ['Widget', 'Gadget', 'Doohickey']; let colors = ['Black', 'White', 'Red', 'Green', 'Blue']; // // generate some random data export function getData(count, currentChangedHdl) { let data = []; let dt = new Date(); // // add count items for (let i = 0; i < count; i++) { // constants used to create data items let date = new Date(dt.getFullYear(), i % 12, 25, i % 24, i % 60, i % 60), countryId = Math.floor(Math.random() * countries.length), productId = Math.floor(Math.random() * products.length), colorId = Math.floor(Math.random() * colors.length); // // add the item to the list data.push({ id: i, start: date, end: date, country: countries[countryId], product: products[productId], color: colors[colorId], countryId: countryId, productId: productId, colorId: colorId, amount: Math.random() * 10000 - 5000, amount2: Math.random() * 10000 - 5000, discount: Math.random() / 4, active: i % 4 == 0 }); } // // return a CollectionView so multiple controls bound to this source // will be updated automatically (TFS 145538) let cv = new CollectionView(data); if (currentChangedHdl) { cv.currentChanged.addHandler(currentChangedHdl); } // return cv; } // // get possible values for each field export function getCountries() { return countries; } // export function getProducts() { return products; } // export function getColors() { return colors; } import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './app.css'; // import * as React from 'react'; // // CollectionView navigator component export class Navigator extends React.Component { // constructor(props) { super(props); this.BtnFirstStyle = { marginRight: '-4px' }; this.BtnLastStyle = { marginLeft: '-4px' }; } // moveCurrentToFirst() { this.props.view.moveCurrentToFirst(); this.forceUpdate(); } // moveCurrentToPrevious() { this.props.view.moveCurrentToPrevious(); this.forceUpdate(); } // moveCurrentToNext() { this.props.view.moveCurrentToNext(); this.forceUpdate(); } // moveCurrentToLast() { this.props.view.moveCurrentToLast(); this.forceUpdate(); } // render() { return <div className='wj-control wj-content wj-pager'> <div className='wj-input-group'> <span className='wj-input-group-btn'> <button type='button' className='wj-btn wj-btn-default' onClick={this.moveCurrentToFirst.bind(this)} disabled={this.props.view.currentPosition <= 0}> <span className='wj-glyph-left' style={this.BtnFirstStyle}></span> <span className='wj-glyph-left'></span> </button> </span> <span className='wj-input-group-btn'> <button type='button' className='wj-btn wj-btn-default' onClick={this.moveCurrentToPrevious.bind(this)} disabled={this.props.view.currentPosition <= 0}> <span className='wj-glyph-left'></span> </button> </span> <input type='text' className='wj-form-control' value={this.props.view.currentPosition + 1 + ' / ' + this.props.view.itemCount} disabled/> <span className='wj-input-group-btn'> <button type='button' className='wj-btn wj-btn-default' onClick={this.moveCurrentToNext.bind(this)} disabled={this.props.view.currentPosition >= this.props.view.itemCount - 1}> <span className='wj-glyph-right'></span> </button> </span> <span className='wj-input-group-btn'> <button type='button' className='wj-btn wj-btn-default' onClick={this.moveCurrentToLast.bind(this)} disabled={this.props.view.currentPosition >= this.props.view.itemCount - 1}> <span className='wj-glyph-right'></span> <span className='wj-glyph-right' style={this.BtnLastStyle}></span> </button> </span> </div> </div>; } }