Sorting (React)

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.

Learn about FlexSheet | FlexSheet API Reference

This example uses React.

import 'bootstrap.css'; import '@mescius/wijmo.styles/wijmo.css'; import ReactDOM from 'react-dom/client'; import React, { useState } from 'react'; import useEvent from 'react-use-event-hook'; import * as wjcSheet from '@mescius/wijmo.grid.sheet'; import * as wjcGrid from '@mescius/wijmo.grid'; import * as wjGridSheet from '@mescius/wijmo.react.grid.sheet'; import './app.css'; import { data, countries, products } from './data'; function App() { const [sortManager, setSortManager] = useState(null); const [columns, setColumns] = useState([]); const [time, setTime] = useState(0); const initializeFlexSheet = useEvent((flex) => { flex.deferUpdate(() => { let column = flex.columns.getColumn("countryId"); if (column && !column.dataMap) { column.dataMap = buildDataMap(countries); } column = flex.columns.getColumn("productId"); if (column && !column.dataMap) { column.width = 100; column.dataMap = buildDataMap(products); } column = flex.columns.getColumn("amount"); if (column) { column.format = "c2"; } setSortManager(flex.sortManager); setColumns(getColumns(flex)); }); flex.selectedSheetChanged.addHandler(() => { setColumns(getColumns(flex)); if (!sortManager) { setSortManager(flex.sortManager); } }); flex.columnChanged.addHandler(() => { setColumns(getColumns(flex)); }); flex.sortManager.sortDescriptions.collectionChanged.addHandler(() => { forceUpdate(); }); }); // commit the sorts const commitSort = () => { sortManager.commitSort(); forceUpdate(); }; // cancel the sorts const cancelSort = () => { sortManager.cancelSort(); forceUpdate(); }; // add new sort level const addSortLevel = () => { sortManager.addSortLevel(); forceUpdate(); }; // delete current sort level const deleteSortLevel = () => { sortManager.deleteSortLevel(); forceUpdate(); }; // copy a new sort level by current sort level setting. const copySortLevel = () => { sortManager.copySortLevel(); forceUpdate(); }; // move the sort level const moveSortLevel = (offset) => { sortManager.moveSortLevel(offset); forceUpdate(); }; // apply column index property for sort item const applySortColumnIndex = (e, sortItem) => { sortItem.columnIndex = e.target.value; }; // apply asceding property for sort item const 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 const 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"); }; const getColumns = (flexSheet) => { let columns = [], i = 0; if (flexSheet) { for (; i < flexSheet.columns.length; i++) { columns.push("Column " + wjcSheet.FlexSheet.convertNumberToAlpha(i)); } } return columns; }; const renderOption = (sortItem, column, i) => { return (<option key={i} selected={(i === sortItem.columnIndex)} value={i}>{column}</option>); }; const getClass = (sortItem) => { let flag = (sortItem === sortManager.sortDescriptions.currentItem); if (flag) { return "success"; } return ""; }; const onTrClick = (sortItem) => { sortManager.sortDescriptions.moveCurrentTo(sortItem); forceUpdate(); }; const renderTr = (sortItem, i) => { const option = columns.map((column, i) => renderOption(sortItem, column, i)); return (<tr key={i} onClick={() => onTrClick(sortItem)} className={getClass(sortItem)}> <td> <select className="form-control" onChange={(e) => applySortColumnIndex(e, sortItem)}> <option value="-1"></option> {option} </select> </td> <td> <select className="form-control" onChange={(e) => applySortAscending(e, sortItem)}> <option value="true" selected={sortItem.ascending}>Ascending</option> <option value="false" selected={!sortItem.ascending}>Descending</option> </select> </td> </tr>); }; const renderTbody = () => { if (!sortManager) { return; } const rows = sortManager.sortDescriptions.items.map((sortItem, i) => renderTr(sortItem, i)); return (<tbody> {rows} </tbody>); }; const forceUpdate = () => { setTime(new Date().getTime()); }; return (<div className="container-fluid"> <wjGridSheet.FlexSheet initialized={initializeFlexSheet}> <wjGridSheet.Sheet name="Country" itemsSource={data}/> </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> {renderTbody()} </table> <div className="btn-group"> <button type="button" className="btn btn-default" onClick={addSortLevel}>Add Level</button> <button type="button" className="btn btn-default" onClick={deleteSortLevel}>Delete Level</button> <button type="button" className="btn btn-default" onClick={copySortLevel}>Copy Level</button> </div> <div className="btn-group"> <button id="moveup" type="button" className="btn btn-default" disabled={sortManager && sortManager.sortDescriptions.currentPosition <= 0} onClick={() => moveSortLevel(-1)}> <span className="glyphicon glyphicon-arrow-up"></span> </button> <button id="movedown" type="button" className="btn btn-default" disabled={sortManager && sortManager.sortDescriptions.currentPosition >= sortManager.sortDescriptions.itemCount - 1} onClick={() => moveSortLevel(1)}> <span className="glyphicon glyphicon-arrow-down"></span> </button> </div> <div className="btn-group"> <button type="button" className="btn btn-default" onClick={commitSort}>OK</button> <button type="button" className="btn btn-default" onClick={cancelSort}>Cancel</button> </div> </div>); } const container = document.getElementById('app'); if (container) { const root = ReactDOM.createRoot(container); root.render(<App />); }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>MESCIUS Wijmo Wijmo FlexSheet Sorting</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.40/system.src.js" integrity="sha512-G6mEj6h18+m3MvzdviSDfPle/TfH0//cXcB33AKlNR/Rha0yQsKefDZKRTkIZos97HEGq2JMV1RT5ybMoQ3WsQ==" crossorigin="anonymous"></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; }
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 const countries = ['US', 'Germany', 'UK', 'Japan', 'Italy', 'Greece']; export const products = ['Widget', 'Gadget', 'Doohickey']; export const data = getData(50);
(function (global) { window.process = { env: { NODE_ENV: "production" } } System.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true, react: true }, meta: { '*.css': { loader: 'css' } }, paths: { // paths serve as alias 'npm:': 'node_modules/' }, // map tells the System loader where to look for things map: { 'jszip': 'npm:jszip/dist/jszip.js', '@mescius/wijmo': 'npm:@mescius/wijmo/index.js', '@mescius/wijmo.input': 'npm:@mescius/wijmo.input/index.js', '@mescius/wijmo.styles': 'npm:@mescius/wijmo.styles', '@mescius/wijmo.cultures': 'npm:@mescius/wijmo.cultures', '@mescius/wijmo.chart': 'npm:@mescius/wijmo.chart/index.js', '@mescius/wijmo.chart.analytics': 'npm:@mescius/wijmo.chart.analytics/index.js', '@mescius/wijmo.chart.animation': 'npm:@mescius/wijmo.chart.animation/index.js', '@mescius/wijmo.chart.annotation': 'npm:@mescius/wijmo.chart.annotation/index.js', '@mescius/wijmo.chart.finance': 'npm:@mescius/wijmo.chart.finance/index.js', '@mescius/wijmo.chart.finance.analytics': 'npm:@mescius/wijmo.chart.finance.analytics/index.js', '@mescius/wijmo.chart.hierarchical': 'npm:@mescius/wijmo.chart.hierarchical/index.js', '@mescius/wijmo.chart.interaction': 'npm:@mescius/wijmo.chart.interaction/index.js', '@mescius/wijmo.chart.radar': 'npm:@mescius/wijmo.chart.radar/index.js', '@mescius/wijmo.chart.render': 'npm:@mescius/wijmo.chart.render/index.js', '@mescius/wijmo.chart.webgl': 'npm:@mescius/wijmo.chart.webgl/index.js', '@mescius/wijmo.chart.map': 'npm:@mescius/wijmo.chart.map/index.js', '@mescius/wijmo.gauge': 'npm:@mescius/wijmo.gauge/index.js', '@mescius/wijmo.grid': 'npm:@mescius/wijmo.grid/index.js', '@mescius/wijmo.grid.detail': 'npm:@mescius/wijmo.grid.detail/index.js', '@mescius/wijmo.grid.filter': 'npm:@mescius/wijmo.grid.filter/index.js', '@mescius/wijmo.grid.search': 'npm:@mescius/wijmo.grid.search/index.js', '@mescius/wijmo.grid.style': 'npm:@mescius/wijmo.grid.style/index.js', '@mescius/wijmo.grid.grouppanel': 'npm:@mescius/wijmo.grid.grouppanel/index.js', '@mescius/wijmo.grid.multirow': 'npm:@mescius/wijmo.grid.multirow/index.js', '@mescius/wijmo.grid.transposed': 'npm:@mescius/wijmo.grid.transposed/index.js', '@mescius/wijmo.grid.transposedmultirow': 'npm:@mescius/wijmo.grid.transposedmultirow/index.js', '@mescius/wijmo.grid.pdf': 'npm:@mescius/wijmo.grid.pdf/index.js', '@mescius/wijmo.grid.sheet': 'npm:@mescius/wijmo.grid.sheet/index.js', '@mescius/wijmo.grid.xlsx': 'npm:@mescius/wijmo.grid.xlsx/index.js', '@mescius/wijmo.grid.selector': 'npm:@mescius/wijmo.grid.selector/index.js', '@mescius/wijmo.grid.cellmaker': 'npm:@mescius/wijmo.grid.cellmaker/index.js', '@mescius/wijmo.grid.immutable': 'npm:@mescius/wijmo.grid.immutable/index.js', '@mescius/wijmo.touch': 'npm:@mescius/wijmo.touch/index.js', '@mescius/wijmo.cloud': 'npm:@mescius/wijmo.cloud/index.js', '@mescius/wijmo.nav': 'npm:@mescius/wijmo.nav/index.js', '@mescius/wijmo.odata': 'npm:@mescius/wijmo.odata/index.js', '@mescius/wijmo.olap': 'npm:@mescius/wijmo.olap/index.js', '@mescius/wijmo.rest': 'npm:@mescius/wijmo.rest/index.js', '@mescius/wijmo.pdf': 'npm:@mescius/wijmo.pdf/index.js', '@mescius/wijmo.pdf.security': 'npm:@mescius/wijmo.pdf.security/index.js', '@mescius/wijmo.viewer': 'npm:@mescius/wijmo.viewer/index.js', '@mescius/wijmo.xlsx': 'npm:@mescius/wijmo.xlsx/index.js', '@mescius/wijmo.undo': 'npm:@mescius/wijmo.undo/index.js', '@mescius/wijmo.interop.grid': 'npm:@mescius/wijmo.interop.grid/index.js', '@mescius/wijmo.barcode': 'npm:@mescius/wijmo.barcode/index.js', '@mescius/wijmo.barcode.common': 'npm:@mescius/wijmo.barcode.common/index.js', '@mescius/wijmo.barcode.composite': 'npm:@mescius/wijmo.barcode.composite/index.js', '@mescius/wijmo.barcode.specialized': 'npm:@mescius/wijmo.barcode.specialized/index.js', "@mescius/wijmo.react.chart.analytics": "npm:@mescius/wijmo.react.chart.analytics/index.js", "@mescius/wijmo.react.chart.animation": "npm:@mescius/wijmo.react.chart.animation/index.js", "@mescius/wijmo.react.chart.annotation": "npm:@mescius/wijmo.react.chart.annotation/index.js", "@mescius/wijmo.react.chart.finance.analytics": "npm:@mescius/wijmo.react.chart.finance.analytics/index.js", "@mescius/wijmo.react.chart.finance": "npm:@mescius/wijmo.react.chart.finance/index.js", "@mescius/wijmo.react.chart.hierarchical": "npm:@mescius/wijmo.react.chart.hierarchical/index.js", "@mescius/wijmo.react.chart.interaction": "npm:@mescius/wijmo.react.chart.interaction/index.js", "@mescius/wijmo.react.chart.radar": "npm:@mescius/wijmo.react.chart.radar/index.js", "@mescius/wijmo.react.chart": "npm:@mescius/wijmo.react.chart/index.js", "@mescius/wijmo.react.core": "npm:@mescius/wijmo.react.core/index.js", '@mescius/wijmo.react.chart.map': 'npm:@mescius/wijmo.react.chart.map/index.js', "@mescius/wijmo.react.gauge": "npm:@mescius/wijmo.react.gauge/index.js", "@mescius/wijmo.react.grid.detail": "npm:@mescius/wijmo.react.grid.detail/index.js", "@mescius/wijmo.react.grid.filter": "npm:@mescius/wijmo.react.grid.filter/index.js", "@mescius/wijmo.react.grid.grouppanel": "npm:@mescius/wijmo.react.grid.grouppanel/index.js", '@mescius/wijmo.react.grid.search': 'npm:@mescius/wijmo.react.grid.search/index.js', "@mescius/wijmo.react.grid.multirow": "npm:@mescius/wijmo.react.grid.multirow/index.js", "@mescius/wijmo.react.grid.sheet": "npm:@mescius/wijmo.react.grid.sheet/index.js", '@mescius/wijmo.react.grid.transposed': 'npm:@mescius/wijmo.react.grid.transposed/index.js', '@mescius/wijmo.react.grid.transposedmultirow': 'npm:@mescius/wijmo.react.grid.transposedmultirow/index.js', '@mescius/wijmo.react.grid.immutable': 'npm:@mescius/wijmo.react.grid.immutable/index.js', "@mescius/wijmo.react.grid": "npm:@mescius/wijmo.react.grid/index.js", "@mescius/wijmo.react.input": "npm:@mescius/wijmo.react.input/index.js", "@mescius/wijmo.react.olap": "npm:@mescius/wijmo.react.olap/index.js", "@mescius/wijmo.react.viewer": "npm:@mescius/wijmo.react.viewer/index.js", "@mescius/wijmo.react.nav": "npm:@mescius/wijmo.react.nav/index.js", "@mescius/wijmo.react.base": "npm:@mescius/wijmo.react.base/index.js", '@mescius/wijmo.react.barcode.common': 'npm:@mescius/wijmo.react.barcode.common/index.js', '@mescius/wijmo.react.barcode.composite': 'npm:@mescius/wijmo.react.barcode.composite/index.js', '@mescius/wijmo.react.barcode.specialized': 'npm:@mescius/wijmo.react.barcode.specialized/index.js', 'jszip': 'npm:jszip/dist/jszip.js', 'react': 'npm:react/index.js', 'react-dom': 'npm:react-dom/index.js', 'react-dom/client': 'npm:react-dom/client.js', "scheduler": "npm:scheduler/index.js", 'redux': 'npm:redux/dist/redux.min.js', 'react-redux': 'npm:react-redux/dist/react-redux.min.js', 'bootstrap.css': 'npm:bootstrap/dist/css/bootstrap.min.css', 'css': 'npm:systemjs-plugin-css/css.js', 'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js', 'systemjs-babel-build':'npm:systemjs-plugin-babel/systemjs-babel-browser.js', "react-use-event-hook": "npm:react-use-event-hook/dist/esm/useEvent.js", }, // packages tells the System loader how to load when no filename and/or no extension packages: { src: { defaultExtension: 'jsx' }, "node_modules": { defaultExtension: 'js' }, } }); })(this);