Introduction

This view shows the FlexGrid control's basic features. It binds the grid to a data source and has menus below that allow you to select the number of data items, the selection mode, and the culture, and whether to use data mapping and formatting. Notice how the grid remains fast and fluid even with large numbers of data items. FlexGrid achieves this level of performance by automatically virtualizing rows and columns.

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">Yes</wj-menu-item> <wj-menu-item [value]="false">No</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">On</wj-menu-item> <wj-menu-item [value]="false">Off</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"> <wj-collection-view-navigator :cv="collectionView" class="pull-right"> </wj-collection-view-navigator> </div> </div> <!-- the grid --> <wj-flex-grid :itemsSource="collectionView" :initialized="initialized" class="grid" :allowResizing="'Both'" :allowMerging="'All'" :stickyHeaders="true" :allowAddNew="allowAddNew" :selectionMode="selectionMode" :headersVisibility="headersVisibility" :showSelectedHeaders="showSelectedHeaders" :showMarquee="showMarquee" ></wj-flex-grid> <!-- commands --> <div class="well"> <div class="grid-sort-group"> <!-- current selection --> <p> Selection: <b>{{selection | cellRange}}</b> </p> <!-- data size --> <wj-menu :value="itemCount" :header="'Items'" :itemClicked="itemClicked.bind(this,'itemCount')"> <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="allowAddNew" :header="'Allow Add'" :itemClicked="itemClicked.bind(this,'allowAddNew')"> <wj-menu-item :value="true">Yes</wj-menu-item> <wj-menu-item :value="false">No</wj-menu-item> </wj-menu> <!-- selection mode --> <wj-menu :value="selectionMode" :header="'Selection'" :itemClicked="itemClicked.bind(this,'selectionMode')"> <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="headersVisibility" :header="'Headers Visibility'" :itemClicked="itemClicked.bind(this,'headersVisibility')"> <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="showSelectedHeaders" :header="'Show Selected Headers'" :itemClicked="itemClicked.bind(this,'showSelectedHeaders')"> <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="showMarquee" :header="'Show Marquee'" :itemClicked="itemClicked.bind(this,'showMarquee')"> <wj-menu-item :value="true">On</wj-menu-item> <wj-menu-item :value="false">Off</wj-menu-item> </wj-menu> <!-- data maps --> <wj-menu :value="dataMaps" :header="'Data Maps'" :itemClicked="itemClicked.bind(this,'dataMaps')"> <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'" :itemClicked="itemClicked.bind(this,'formatting')"> <wj-menu-item :value="true">On</wj-menu-item> <wj-menu-item :value="false">Off</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> </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", created: function() { this.dataArray = getData(this.itemCount); }, data: { dataMaps: true, formatting: true, filter: '', selection: null, allowAddNew: false, selectionMode: wjcGrid.SelectionMode.CellRange, headersVisibility: wjcGrid.HeadersVisibility.All, showSelectedHeaders: wjcGrid.HeadersVisibility.None, showMarquee: false, itemCount: 500, collectionView: new wjcCore.CollectionView(), dataArray: null }, watch: { dataMaps: function (newVal, oldVal) { console.log('dataMaps watcher'); this._updateDataMaps(); }, dataArray: function(newVal, oldVal) { console.log('dataArray watcher'); this.collectionView.sourceCollection = newVal; let flex = this.flex; // if it's the first assignment to dataArray if (oldVal == null && flex) { // make columns 25% wider (for readability and to show how) for (let i = 0; i < flex.columns.length; i++) { flex.columns[i].width = flex.columns[i].renderSize * 1.25; } } this.updateDataMapSettings(); }, itemCount: function(newVal) { console.log('itemCount watcher'); this.dataArray = getData(newVal); }, formatting: function() { this._updateFormatting(); }, filter: function() { this._applyFilter(); } }, methods: { initialized: function(flex) { this.flex = flex; this.selection = this.flex.selection; this.flex.selectionChanged.addHandler((s, e) => { this.selection = e.range; }); this.flex.select(new wjcGrid.CellRange(0, 0)); }, updateDataMapSettings: function() { this._updateDataMaps(); this._updateFormatting(); }, toggleColumnVisibility: function() { let flex = this.flex, col = flex.columns[0]; col.visible = !col.visible; }, changeColumnSize: function() { let flex = this.flex, 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() { let flex = this.flex, row = flex.rows[0]; row.visible = !row.visible; }, changeRowSize: function() { let flex = this.flex, row = flex.rows[0]; row.visible = true; row.height = row.height == null ? 80 : null; row = flex.columnHeaders.rows[0]; row.height = row.height == null ? 80 : null; }, changeDefaultRowSize: function() { let flex = this.flex; flex.rows.defaultSize = flex.rows.defaultSize == 28 ? 65 : 28; }, changeScrollPosition: function() { let flex = this.flex; if (flex.scrollPosition.y == 0) { let 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() { let flex = this.flex; if (flex) { let colCountry = flex.columns.getColumn("countryId"), colProduct = flex.columns.getColumn("productId"), colColor = flex.columns.getColumn("colorId"); if (colCountry && colProduct && colColor) { if (this.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 = 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) { let map = []; for (let 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() { let flex = this.flex; if (flex) { 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: function(name, format) { let col = this.flex.columns.getColumn(name); if (col) { col.format = format; } }, // apply filter (applied on a 500 ms timeOut) _applyFilter: function() { if (this.filterTimeOut) { clearTimeout(this.filterTimeOut); } this.filterTimeOut = setTimeout(() => { this.filterTimeOut = null; if (this.collectionView) { let cv = this.collectionView; if (cv) { if (cv.filter != this.filterFunction) { cv.filter = this.filterFunction; } else { cv.refresh(); } } } }, 500); }, itemClicked: function(prop, s, e) { if (s.selectedIndex > -1) { this[prop] = s.selectedValue; } }, filterFunction: function(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 ( 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; } }, filters: { // formats grid selection range to display its value to a user cellRange: function (value) { let rng = ""; if (value instanceof wjcGrid.CellRange) { rng = "(" + value.row + ";" + value.col + ")"; if (!value.isSingleCell) { rng += "-(" + value.row2 + ";" + value.col2 + ")"; } } return rng; } }, }); </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._toFilter = null; this._itemsCount = 500; this.state = { allowAdd: false, dataMaps: true, filter: '', formatting: true, headersVisibility: 3, selectionMode: 2, showMarquee: false, showSelectedHeaders: 0, data: getData(this._itemsCount), selection: '' }; } 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}> </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='Items' value={this.itemsCount} itemClicked={this._menuChanged.bind(this, MenuType.itemsCount)}> <wjInput.MenuItem value={5}>5</wjInput.MenuItem> <wjInput.MenuItem value={50}>50</wjInput.MenuItem> <wjInput.MenuItem value={500}>500</wjInput.MenuItem> <wjInput.MenuItem value={5000}>5,000</wjInput.MenuItem> <wjInput.MenuItem value={50000}>50,000</wjInput.MenuItem> <wjInput.MenuItem value={100000}>100,000</wjInput.MenuItem> <wjInput.MenuItem value={500000}>500,000</wjInput.MenuItem> <wjInput.MenuItem value={1000000}>1,000,000</wjInput.MenuItem> </wjInput.Menu> <wjInput.Menu header='Allow Add' value={this.allowAdd} itemClicked={this._menuChanged.bind(this, MenuType.allowAdd)}> <wjInput.MenuItem value={true}>Yes</wjInput.MenuItem> <wjInput.MenuItem value={false}>No</wjInput.MenuItem> </wjInput.Menu> <wjInput.Menu header='Selection' value={this.selectionMode} itemClicked={this._menuChanged.bind(this, MenuType.selectionMode)}> <wjInput.MenuItem value={0}>None</wjInput.MenuItem> <wjInput.MenuItem value={1}>Cell</wjInput.MenuItem> <wjInput.MenuItem value={2}>CellRange</wjInput.MenuItem> <wjInput.MenuItem value={3}>Row</wjInput.MenuItem> <wjInput.MenuItem value={4}>RowRange</wjInput.MenuItem> <wjInput.MenuItem value={5}>ListBox</wjInput.MenuItem> </wjInput.Menu> <wjInput.Menu header='Headers Visibility' value={this.headersVisibility} itemClicked={this._menuChanged.bind(this, MenuType.headersVisibility)}> <wjInput.MenuItem value={0}>None</wjInput.MenuItem> <wjInput.MenuItem value={1}>Column</wjInput.MenuItem> <wjInput.MenuItem value={2}>Row</wjInput.MenuItem> <wjInput.MenuItem value={3}>All</wjInput.MenuItem> </wjInput.Menu> <wjInput.Menu header='Show Selected Headers' value={this.showSelectedHeaders} itemClicked={this._menuChanged.bind(this, MenuType.showSelectedHeaders)}> <wjInput.MenuItem value={0}>None</wjInput.MenuItem> <wjInput.MenuItem value={1}>Column</wjInput.MenuItem> <wjInput.MenuItem value={2}>Row</wjInput.MenuItem> <wjInput.MenuItem value={3}>All</wjInput.MenuItem> </wjInput.Menu> <wjInput.Menu header='Show Marquee' value={this.showMarquee} itemClicked={this._menuChanged.bind(this, MenuType.showMarquee)}> <wjInput.MenuItem value={true}>On</wjInput.MenuItem> <wjInput.MenuItem value={false}>Off</wjInput.MenuItem> </wjInput.Menu> <wjInput.Menu header='Data Maps' value={this.dataMaps} itemClicked={this._menuChanged.bind(this, MenuType.dataMaps)}> <wjInput.MenuItem value={true}>On</wjInput.MenuItem> <wjInput.MenuItem value={false}>Off</wjInput.MenuItem> </wjInput.Menu> <wjInput.Menu header='Formatting' value={this.formatting} itemClicked={this._menuChanged.bind(this, MenuType.formatting)}> <wjInput.MenuItem value={true}>On</wjInput.MenuItem> <wjInput.MenuItem value={false}>Off</wjInput.MenuItem> </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>; } // 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(); } // // 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' }; } render() { return <div className='wj-control wj-content wj-pager pull-right'> <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>; } 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(); } }