Sorting

FlexSheet can be sorted by any of its columns. The SortManager helps FlexSheet to manage the sort process. The following example uses SortManager to specify the order of the sorting, add or remove sort columns, and change the order of the sort columns.

import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './styles.css'; import * as wjCore from '@grapecity/wijmo'; import * as wjGrid from '@grapecity/wijmo.grid'; import * as wjFlexSheet from '@grapecity/wijmo.grid.sheet'; import { getData, getCountries, getProducts } from './data'; // document.readyState === 'complete' ? init() : window.onload = init; // function init() { let sortSheet = new wjFlexSheet.FlexSheet('#sortSheet'); sortSheet.addBoundSheet('Country', getData(50)); sortSheet.deferUpdate(() => { let column = sortSheet.columns.getColumn('countryId'); if (column && !column.dataMap) { column.dataMap = buildDataMap(getCountries()); } column = sortSheet.columns.getColumn('productId'); if (column && !column.dataMap) { column.dataMap = buildDataMap(getProducts()); } column = sortSheet.columns.getColumn('amount'); if (column) { column.format = 'c2'; } }); let sortManager = sortSheet.sortManager; updateSortTable(); onClick('addLevel', addSortLevel); onClick('delLevel', deleteSortLevel); onClick('copyLevel', copySortLevel); onClick('moveup', () => { moveSortLevel(-1); }); onClick('movedown', () => { moveSortLevel(1); }); onClick('commitSort', commitSort); onClick('cancelSort', cancelSort); sortSheet.selectedSheetChanged.addHandler(() => { updateSortTable(); }); sortManager.sortDescriptions.collectionChanged.addHandler(() => { updateSortTable(); }); sortManager.sortDescriptions.currentChanged.addHandler(() => { updateSortTable(); }); function updateSortTable() { let sortTableBody = document.querySelector('#sortTable tbody'), tRows = '', columns = getColumns(), sortItem; for (let index = 0; index < sortManager.sortDescriptions.itemCount; index++) { sortItem = sortManager.sortDescriptions.items[index]; tRows += '<tr class="' + (sortManager.sortDescriptions.currentPosition === index ? 'success"' : '"') + '><td>' + updateColumnSelect(columns, sortItem) + '</td>'; tRows += '<td><select class="form-control" onchange=""><option value="0"' + ((!sortItem || sortItem.ascending) ? ' selected="selected">' : '>') + 'Ascending</option>' + '<option value="1"' + ((sortItem && !sortItem.ascending) ? ' selected="selected">' : '>') + 'Descending</option></select></td></tr>'; } sortTableBody.innerHTML = tRows; let sortRows = sortTableBody.querySelectorAll('tr'); for (let rowIndex = 0; rowIndex < sortRows.length; rowIndex++) { sortRows[rowIndex].addEventListener('click', () => { sortManager.sortDescriptions.moveCurrentToPosition(rowIndex); updateActiveRow(); }); } let columnSelects = sortTableBody.querySelectorAll('tr td:first-child select'), ascendingSelects = sortTableBody.querySelectorAll('tr td:last-child select'); for (let sortIndex = 0; sortIndex < columnSelects.length; sortIndex++) { sortItem = sortManager.sortDescriptions.items[sortIndex]; columnSelects[sortIndex].addEventListener('change', (e) => { sortItem.columnIndex = e.target.selectedIndex - 1; }); ascendingSelects[sortIndex].addEventListener('change', (e) => { sortItem.ascending = e.target.selectedIndex === 0; }); } updateMoveButtonState(); } function updateActiveRow() { let sortTableBody = document.querySelector('#sortTable tbody'), sortRows = sortTableBody.querySelectorAll('tr'); removeSuccessClass(sortRows); wjCore.addClass(sortRows[sortManager.sortDescriptions.currentPosition], 'success'); } function removeSuccessClass(sortRows) { for (let rowIndex = 0; rowIndex < sortRows.length; rowIndex++) { wjCore.removeClass(sortRows[rowIndex], 'success'); } } function updateColumnSelect(columns, sortItem) { let colSelect = '<select class="form-control"><option value=-1></option>'; for (let index = 0; index < columns.length; index++) { colSelect += '<option ' + ((sortItem && sortItem.columnIndex === index) ? 'selected="selected" ' : '') + ' value="' + index + '">' + columns[index] + '</option>'; } colSelect += '</select>'; return colSelect; } function updateMoveButtonState() { let moveupBtn = document.querySelector('#moveup'), movedownBtn = document.querySelector('#movedown'); if (sortManager.sortDescriptions.currentPosition === 0) { moveupBtn.setAttribute('disabled', 'true'); } else { moveupBtn.removeAttribute('disabled'); } if (sortManager.sortDescriptions.currentPosition === sortManager.sortDescriptions.itemCount - 1) { movedownBtn.setAttribute('disabled', 'true'); } else { movedownBtn.removeAttribute('disabled'); } } // get the columns with the column header text for the column selection for sort setting. function getColumns() { var columns = [], i = 0; if (sortSheet) { for (; i < sortSheet.columns.length; i++) { columns.push('Column ' + wjFlexSheet.FlexSheet.convertNumberToAlpha(i)); } } return columns; } // commit the sorts function commitSort() { sortManager.commitSort(); } // cancel the sorts function cancelSort() { sortManager.cancelSort(); updateActiveRow(); } // add new sort level function addSortLevel() { sortManager.addSortLevel(); updateActiveRow(); } // delete current sort level function deleteSortLevel() { sortManager.deleteSortLevel(); updateActiveRow(); } // copy a new sort level by current sort level setting. function copySortLevel() { sortManager.copySortLevel(); updateActiveRow(); } // move the sort level function moveSortLevel(offset) { sortManager.moveSortLevel(offset); updateActiveRow(); } // build a data map from a string array using the indices as keys function buildDataMap(items) { let map = []; for (let i = 0; i < items.length; i++) { map.push({ key: i, value: items[i] }); } return new wjGrid.DataMap(map, 'key', 'value'); } ; function onClick(id, fn) { document.querySelector('#' + id).addEventListener('click', fn); } } <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity Wijmo FlexSheet Sorting</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 id="sortSheet"></div> <table id="sortTable" class="table table-bordered"> <thead> <tr> <th class="text-center">Column</th> <th class="text-center">Order</th> </tr> </thead> <tbody> </tbody> </table> <div class="btn-group"> <button id="addLevel" type="button" class="btn btn-default"> Add Level </button> <button id="delLevel" type="button" class="btn btn-default"> Delete Level </button> <button id="copyLevel" type="button" class="btn btn-default"> Copy Level </button> </div> <div class="btn-group"> <button id="moveup" type="button" class="btn btn-default"> <span class="glyphicon glyphicon-arrow-up"></span> </button> <button id="movedown" type="button" class="btn btn-default"> <span class="glyphicon glyphicon-arrow-down"></span> </button> </div> <div class="btn-group"> <button id="commitSort" type="button" class="btn btn-default">OK</button> <button id="cancelSort" type="button" class="btn btn-default">Cancel</button> </div> </div> </body> </html> let countries = ['US', 'Germany', 'UK', 'Japan', 'Italy', 'Greece'], products = ['Widget', 'Gadget', 'Doohickey']; export function getData(count) { let data = [], i = 0, countryId, productId; for (; i < count; i++) { countryId = Math.floor(Math.random() * countries.length); productId = Math.floor(Math.random() * products.length); data.push({ id: i, countryId: countryId, productId: productId, date: new Date(2014, i % 12, i % 28), amount: Math.random() * 10000, active: i % 4 === 0 }); } return data; } export function getCountries() { return countries; } export function getProducts() { return products; } .wj-flexsheet { height: 400px; margin: 6px 0; } import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './styles.css'; import { Component, enableProdMode, NgModule, Inject } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { BrowserModule } from '@angular/platform-browser'; import { WjGridSheetModule } from '@grapecity/wijmo.angular2.grid.sheet'; import * as wjcGrid from '@grapecity/wijmo.grid'; import * as wjcSheet from '@grapecity/wijmo.grid.sheet'; import { DataService } from './app.data'; @Component({ selector: 'app-component', templateUrl: 'src/app.component.html' }) export class AppComponent { data: any[]; sortManager: wjcSheet.SortManager; columns: string[]; private _countries: string[]; private _products: string[]; constructor(@Inject(DataService) dataSvc: DataService) { this.data = dataSvc.getData(50); this._countries = dataSvc.countries; this._products = dataSvc.products; } initializeFlexSheet(flex: wjcSheet.FlexSheet) { flex.deferUpdate(() => { let column = flex.columns.getColumn('countryId'); if (column && !column.dataMap) { column.dataMap = this._buildDataMap(this._countries); } column = flex.columns.getColumn('productId'); if (column && !column.dataMap) { column.width = 100; column.dataMap = this._buildDataMap(this._products); } column = flex.columns.getColumn('amount'); if (column) { column.format = 'c2'; } this.sortManager = flex.sortManager; this.columns = this._getColumns(flex); }); flex.selectedSheetChanged.addHandler(() => { this.columns = this._getColumns(flex); if (!this.sortManager) { this.sortManager = flex.sortManager; } }); flex.columnChanged.addHandler(() => { this.columns = this._getColumns(flex); }); } // commit the sorts commitSort() { this.sortManager.commitSort(); }; // cancel the sorts cancelSort() { this.sortManager.cancelSort(); }; // add new sort level addSortLevel() { this.sortManager.addSortLevel(); }; // delete current sort level deleteSortLevel() { this.sortManager.deleteSortLevel(); }; // copy a new sort level by current sort level setting. copySortLevel() { this.sortManager.copySortLevel(); }; // move the sort level moveSortLevel(offset: number) { this.sortManager.moveSortLevel(offset); }; // apply column index property for sort item applySortColumnIndex(e: any, sortItem: wjcSheet.ColumnSortDescription) { sortItem.columnIndex = +e.target.value; } // apply asceding property for sort item applySortAscending(e: any, sortItem: wjcSheet.ColumnSortDescription) { if (e.target.value === 'true') { sortItem.ascending = true; } else { sortItem.ascending = false; } } // build a data map from a string array using the indices as keys private _buildDataMap(items: string[]) { let map = []; for (let i = 0; i < items.length; i++) { map.push({ key: i, value: items[i] }); } return new wjcGrid.DataMap(map, 'key', 'value'); } private _getColumns(flexSheet: wjcSheet.FlexSheet): string[] { let columns = [], i = 0; if (flexSheet) { for (; i < flexSheet.columns.length; i++) { columns.push('Column ' + wjcSheet.FlexSheet.convertNumberToAlpha(i)); } } return columns; } } @NgModule({ imports: [WjGridSheetModule, BrowserModule], providers: [DataService], declarations: [AppComponent], 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 FlexSheet Sorting</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"> <!-- the flexsheet --> <wj-flex-sheet #flex (initialized)="initializeFlexSheet(flex)"> <wj-sheet [name]="'Country'" [(itemsSource)]="data"></wj-sheet> </wj-flex-sheet> <table class="table table-bordered"> <thead> <tr> <th class="text-center" style="width: 50%;">Column</th> <th class="text-center" style="width: 50%;">Order</th> </tr> </thead> <tbody *ngIf="sortManager"> <tr *ngFor="let sortItem of sortManager.sortDescriptions.items" (click)="sortManager.sortDescriptions.moveCurrentTo(sortItem)" [ngClass]="{success: sortItem === sortManager.sortDescriptions.currentItem}"> <td> <select class="form-control" (change)="applySortColumnIndex($event, sortItem)"> <option value=-1></option> <option *ngFor="let column of columns; let i = index" [selected]="i === sortItem.columnIndex" value={{i}}> {{column}} </option> </select> </td> <td> <select class="form-control" (change)="applySortAscending($event, sortItem)"> <option [value]="true" [selected]="sortItem.ascending">Ascending</option> <option [value]="false" [selected]="!sortItem.ascending">Descending</option> </select> </td> </tr> </tbody> </table> <div class="btn-group"> <button type="button" class="btn btn-default" (click)="addSortLevel()"> Add Level </button> <button type="button" class="btn btn-default" (click)="deleteSortLevel()"> Delete Level </button> <button type="button" class="btn btn-default" (click)="copySortLevel()"> Copy Level </button> </div> <div class="btn-group"> <button id="moveup" type="button" class="btn btn-default" [disabled]="sortManager && sortManager.sortDescriptions.currentPosition <= 0" (click)="moveSortLevel(-1)"> <span class="glyphicon glyphicon-arrow-up"></span> </button> <button id="movedown" type="button" class="btn btn-default" [disabled]="sortManager && sortManager.sortDescriptions.currentPosition >= sortManager.sortDescriptions.itemCount - 1" (click)="moveSortLevel(1)"> <span class="glyphicon glyphicon-arrow-down"></span> </button> </div> <div class="btn-group"> <button type="button" class="btn btn-default" (click)="commitSort()">OK</button> <button type="button" class="btn btn-default" (click)="cancelSort()">Cancel</button> </div> </div> import { Injectable } from '@angular/core'; @Injectable() export class DataService { countries = ['US', 'Germany', 'UK', 'Japan', 'Italy', 'Greece']; products = ['Widget', 'Gadget', 'Doohickey']; getData(count: number) { let data = [], i = 0, countryId, productId; for (; i < count; i++) { countryId = Math.floor(Math.random() * this.countries.length); productId = Math.floor(Math.random() * this.products.length); data.push({ id: i, countryId: countryId, productId: productId, date: new Date(2014, i % 12, i % 28), amount: Math.random() * 10000, active: i % 4 === 0 }); } return data; } } .wj-flexsheet { height: 400px; margin: 6px 0; } <template> <div class="container-fluid"> <!-- the flexsheet --> <wj-flex-sheet :initialized="initializeFlexSheet"> <wj-sheet :name="'Country'" :itemsSource="data"></wj-sheet> </wj-flex-sheet> <table class="table table-bordered"> <thead> <tr> <th class="text-center" style="width: 50%;">Column</th> <th class="text-center" style="width: 50%;">Order</th> </tr> </thead> <tbody v-if="sortManager"> <tr v-for="(sortItem,index) of sortManager.sortDescriptions.items" :key="index" @click="sortManager.sortDescriptions.moveCurrentTo(sortItem)" :class="{success: sortItem === sortManager.sortDescriptions.currentItem}" > <td> <select class="form-control" @change="applySortColumnIndex($event, sortItem)" > <option value="-1"></option> <option v-for="(column,i) of columns" :key="i" :selected="i === sortItem.columnIndex" :value="i" >{{column}}</option> </select> </td> <td> <select class="form-control" @change="applySortAscending($event, sortItem)"> <option :value="true" :selected="sortItem.ascending">Ascending</option> <option :value="false" :selected="!sortItem.ascending">Descending</option> </select> </td> </tr> </tbody> </table> <div class="btn-group"> <button type="button" class="btn btn-default" @click="addSortLevel">Add Level</button> <button type="button" class="btn btn-default" @click="deleteSortLevel">Delete Level</button> <button type="button" class="btn btn-default" @click="copySortLevel">Copy Level</button> </div> <div class="btn-group"> <button id="moveup" type="button" class="btn btn-default" :disabled="sortManager && sortManager.sortDescriptions.currentPosition <= 0" @click="moveSortLevel(-1)" > <span class="glyphicon glyphicon-arrow-up"></span> </button> <button id="movedown" type="button" class="btn btn-default" :disabled="sortManager && sortManager.sortDescriptions.currentPosition >= sortManager.sortDescriptions.itemCount - 1" @click="moveSortLevel(1)" > <span class="glyphicon glyphicon-arrow-down"></span> </button> </div> <div class="btn-group"> <button type="button" class="btn btn-default" @click="commitSort">OK</button> <button type="button" class="btn btn-default" @click="cancelSort">Cancel</button> </div> </div> </template> <script> import "@grapecity/wijmo.styles/wijmo.css"; import "bootstrap.css"; import Vue from "vue"; import '@grapecity/wijmo.vue2.grid.sheet'; import * as wjcGrid from '@grapecity/wijmo.grid'; import * as wjcSheet from '@grapecity/wijmo.grid.sheet'; import { getData, getCountries, getProducts } from "./data"; let App = Vue.extend({ name: "app", data: function() { return { data: getData(50), sortManager: null, columns: [], countries: getCountries(), products: getProducts() }; }, methods: { initializeFlexSheet: function(flex) { flex.deferUpdate(() => { let column = flex.columns.getColumn("countryId"); if (column && !column.dataMap) { column.dataMap = this._buildDataMap(this.countries); } column = flex.columns.getColumn("productId"); if (column && !column.dataMap) { column.width = 100; column.dataMap = this._buildDataMap(this.products); } column = flex.columns.getColumn("amount"); if (column) { column.format = "c2"; } this.sortManager = flex.sortManager; this.columns = this._getColumns(flex); }); flex.selectedSheetChanged.addHandler(() => { this.columns = this._getColumns(flex); if (!this.sortManager) { this.sortManager = flex.sortManager; } }); flex.columnChanged.addHandler(() => { this.columns = this._getColumns(flex); }); }, // commit the sorts commitSort: function() { this.sortManager.commitSort(); }, // cancel the sorts cancelSort: function() { this.sortManager.cancelSort(); }, // add new sort level addSortLevel: function() { this.sortManager.addSortLevel(); }, // delete current sort level deleteSortLevel: function() { this.sortManager.deleteSortLevel(); }, // copy a new sort level by current sort level setting. copySortLevel: function() { this.sortManager.copySortLevel(); }, // move the sort level moveSortLevel: function(offset) { this.sortManager.moveSortLevel(offset); }, // apply column index property for sort item applySortColumnIndex: function(e, sortItem) { sortItem.columnIndex = e.target.value; }, // apply asceding property for sort item applySortAscending: function(e, sortItem) { if (e.target.value === "true") { sortItem.ascending = true; } else { sortItem.ascending = false; } }, // 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"); }, _getColumns: function(flexSheet) { let columns = [], i = 0; if (flexSheet) { for (; i < flexSheet.columns.length; i++) { columns.push( "Column " + wjcSheet.FlexSheet.convertNumberToAlpha(i) ); } } return columns; } } }); new Vue({ render: h => h(App) }).$mount("#app"); </script> <style> .container-fluid .wj-flexsheet { height: 400px; margin: 6px 0; } </style> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>AutoComplete</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="node_modules/jszip/dist/jszip.js"></script> <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> let countries = ['US', 'Germany', 'UK', 'Japan', 'Italy', 'Greece'], products = ['Widget', 'Gadget', 'Doohickey']; export function getData(count) { let data = [], i = 0, countryId, productId; for (; i < count; i++) { countryId = Math.floor(Math.random() * countries.length); productId = Math.floor(Math.random() * products.length); data.push({ id: i, countryId: countryId, productId: productId, date: new Date(2014, i % 12, i % 28), amount: Math.random() * 10000, active: i % 4 === 0 }); } return data; } export function getCountries() { return countries; } export function getProducts() { return products; } import './app.css'; import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; // import * as React from 'react'; import * as ReactDOM from 'react-dom'; // import * as wjcSheet from "@grapecity/wijmo.grid.sheet"; import * as wjcGrid from "@grapecity/wijmo.grid"; import * as wjGridSheet from "@grapecity/wijmo.react.grid.sheet"; import { getData, getCountries, getProducts } from "./data"; class App extends React.Component { constructor(props) { super(props); this.state = { data: getData(50), sortManager: null, columns: [], countries: getCountries(), products: getProducts() }; } render() { return (<div className="container-fluid"> <wjGridSheet.FlexSheet initialized={this.initializeFlexSheet.bind(this)}> <wjGridSheet.Sheet name="Country" itemsSource={this.state.data}></wjGridSheet.Sheet> </wjGridSheet.FlexSheet> <table className="table table-bordered"> <thead> <tr> <th className="text-center" style={{ width: "50%" }}>Column</th> <th className="text-center" style={{ width: "50%" }}>Order</th> </tr> </thead> {this.renderTbody()} </table> <div className="btn-group"> <button type="button" className="btn btn-default" onClick={this.addSortLevel.bind(this)}>Add Level</button> <button type="button" className="btn btn-default" onClick={this.deleteSortLevel.bind(this)}>Delete Level</button> <button type="button" className="btn btn-default" onClick={this.copySortLevel.bind(this)}>Copy Level</button> </div> <div className="btn-group"> <button id="moveup" type="button" className="btn btn-default" disabled={this.state.sortManager && this.state.sortManager.sortDescriptions.currentPosition <= 0} onClick={() => this.moveSortLevel(-1)}> <span className="glyphicon glyphicon-arrow-up"></span> </button> <button id="movedown" type="button" className="btn btn-default" disabled={this.state.sortManager && this.state.sortManager.sortDescriptions.currentPosition >= this.state.sortManager.sortDescriptions.itemCount - 1} onClick={() => this.moveSortLevel(1)}> <span className="glyphicon glyphicon-arrow-down"></span> </button> </div> <div className="btn-group"> <button type="button" className="btn btn-default" onClick={this.commitSort.bind(this)}>OK</button> <button type="button" className="btn btn-default" onClick={this.cancelSort.bind(this)}>Cancel</button> </div> </div>); } initializeFlexSheet(flex) { flex.deferUpdate(() => { let column = flex.columns.getColumn("countryId"); if (column && !column.dataMap) { column.dataMap = this._buildDataMap(this.state.countries); } column = flex.columns.getColumn("productId"); if (column && !column.dataMap) { column.width = 100; column.dataMap = this._buildDataMap(this.state.products); } column = flex.columns.getColumn("amount"); if (column) { column.format = "c2"; } this.setState({ sortManager: flex.sortManager, columns: this._getColumns(flex) }); }); flex.selectedSheetChanged.addHandler(() => { this.setState({ columns: this._getColumns(flex) }); if (!this.state.sortManager) { this.setState({ sortManage: flex.sortManager, }); } }); flex.columnChanged.addHandler(() => { this.setState({ columns: this._getColumns(flex) }); }); } // commit the sorts commitSort() { this.state.sortManager.commitSort(); this.forceUpdate(); } // cancel the sorts cancelSort() { this.state.sortManager.cancelSort(); this.forceUpdate(); } // add new sort level addSortLevel() { this.state.sortManager.addSortLevel(); this.forceUpdate(); } // delete current sort level deleteSortLevel() { this.state.sortManager.deleteSortLevel(); this.forceUpdate(); } // copy a new sort level by current sort level setting. copySortLevel() { this.state.sortManager.copySortLevel(); this.forceUpdate(); } // move the sort level moveSortLevel(offset) { this.state.sortManager.moveSortLevel(offset); this.forceUpdate(); } // apply column index property for sort item applySortColumnIndex(e, sortItem) { sortItem.columnIndex = e.target.value; } // apply asceding property for sort item applySortAscending(e, sortItem) { if (e.target.value === "true") { sortItem.ascending = true; } else { sortItem.ascending = false; } } // build a data map from a string array using the indices as keys _buildDataMap(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"); } _getColumns(flexSheet) { let columns = [], i = 0; if (flexSheet) { for (; i < flexSheet.columns.length; i++) { columns.push("Column " + wjcSheet.FlexSheet.convertNumberToAlpha(i)); } } return columns; } renderOption(sortItem, column, i) { return (<option key={i} selected={(i === sortItem.columnIndex)} value={i}>{column}</option>); } getClass(sortItem) { let flag = (sortItem === this.state.sortManager.sortDescriptions.currentItem); if (flag) { return "success"; } return ""; } onTrClick(sortItem) { this.state.sortManager.sortDescriptions.moveCurrentTo(sortItem); this.forceUpdate(); } renderTr(sortItem, i) { let option = []; this.state.columns.forEach((column, i) => { option.push(this.renderOption(sortItem, column, i)); }); return (<tr key={i} onClick={() => this.onTrClick(sortItem)} className={this.getClass(sortItem)}> <td> <select className="form-control" onChange={(e) => this.applySortColumnIndex(e, sortItem)}> <option value="-1"></option> {option} </select> </td> <td> <select className="form-control" onChange={(e) => this.applySortAscending(e, sortItem)}> <option value="true" selected={sortItem.ascending}>Ascending</option> <option value="false" selected={!sortItem.ascending}>Descending</option> </select> </td> </tr>); } renderTbody() { if (!this.state.sortManager) { return; } let tr = []; this.state.sortManager.sortDescriptions.items.forEach((sortItem, i) => { tr.push(this.renderTr(sortItem, i)); }); return (<tbody> {tr} </tbody>); } } 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>AutoComplete</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> .container-fluid .wj-flexsheet { height: 400px; margin: 6px 0; } let countries = ['US', 'Germany', 'UK', 'Japan', 'Italy', 'Greece'], products = ['Widget', 'Gadget', 'Doohickey']; export function getData(count) { let data = [], i = 0, countryId, productId; for (; i < count; i++) { countryId = Math.floor(Math.random() * countries.length); productId = Math.floor(Math.random() * products.length); data.push({ id: i, countryId: countryId, productId: productId, date: new Date(2014, i % 12, i % 28), amount: Math.random() * 10000, active: i % 4 === 0 }); } return data; } export function getCountries() { return countries; } export function getProducts() { return products; }