Sorting (Angular)

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 Angular.

The demo is being dynamically compiled to support real-time code editing... For quicker access to features, switch to the "JavaScript" tab for a smoother experience! :)
app.component.ts
index.html
app.component.html
app.data.ts
styles.css
Copy to CodeMine
loading...
import 'bootstrap.css'; import '@mescius/wijmo.styles/wijmo.css'; import './styles.css'; import '@angular/compiler'; import { Component, enableProdMode, Inject, ɵresolveComponentResources } from '@angular/core'; import { BrowserModule, bootstrapApplication } from '@angular/platform-browser'; import { WjGridSheetModule } from '@mescius/wijmo.angular2.grid.sheet'; import * as wjcGrid from '@mescius/wijmo.grid'; import * as wjcSheet from '@mescius/wijmo.grid.sheet'; import { DataService } from './app.data'; @Component({ standalone: true, providers: [DataService], imports: [WjGridSheetModule, BrowserModule], 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; } } enableProdMode(); // Resolve resources (templateUrl, styleUrls etc), After resolution all URLs have been converted into `template` strings. ɵresolveComponentResources(fetch).then(() => { // Bootstrap application bootstrapApplication(AppComponent).catch((err) => console.error(err)); });
import 'bootstrap.css'; import '@mescius/wijmo.styles/wijmo.css'; import './styles.css'; import '@angular/compiler'; import { Component, enableProdMode, Inject, ɵresolveComponentResources } from '@angular/core'; import { BrowserModule, bootstrapApplication } from '@angular/platform-browser'; import { WjGridSheetModule } from '@mescius/wijmo.angular2.grid.sheet'; import * as wjcGrid from '@mescius/wijmo.grid'; import * as wjcSheet from '@mescius/wijmo.grid.sheet'; import { DataService } from './app.data'; @Component({ standalone: true, providers: [DataService], imports: [WjGridSheetModule, BrowserModule], 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; } } enableProdMode(); // Resolve resources (templateUrl, styleUrls etc), After resolution all URLs have been converted into `template` strings. ɵresolveComponentResources(fetch).then(() => { // Bootstrap application bootstrapApplication(AppComponent).catch((err) => console.error(err)); });
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>MESCIUS 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/fesm2015/zone.min.js"></script> <!-- SystemJS --> <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.21.5/system.src.js" integrity="sha512-skZbMyvYdNoZfLmiGn5ii6KmklM82rYX2uWctBhzaXPxJgiv4XBwJnFGr5k8s+6tE1pcR1nuTKghozJHyzMcoA==" crossorigin="anonymous"></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; }
(function (global) { SystemJS.config({ transpiler: './plugin-typescript.js', typescriptOptions: { "target": "ES2022", "module": "system", "emitDecoratorMetadata": true, "experimentalDecorators": true, }, baseURL: 'node_modules/', meta: { 'typescript': { "exports": "ts" }, '*.css': { loader: 'systemjs-plugin-css' }, '*.mjs': { format: 'esm' }, }, paths: { // paths serve as alias 'npm:': '' }, packageConfigPaths: [ '/node_modules/*/package.json', "/node_modules/@angular/*/package.json", "/node_modules/@mescius/*/package.json" ], map: { 'core-js': 'https://cdn.jsdelivr.net/npm/core-js@2.6.12/client/shim.min.js', 'typescript': 'https://cdnjs.cloudflare.com/ajax/libs/typescript/5.2.2/typescript.min.js', "rxjs": "https://cdnjs.cloudflare.com/ajax/libs/rxjs/7.8.1/rxjs.umd.min.js", 'systemjs-plugin-css': 'https://cdn.jsdelivr.net/npm/systemjs-plugin-css@0.1.37/css.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.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.touch': 'npm:@mescius/wijmo.touch/index.js', '@mescius/wijmo.cloud': 'npm:@mescius/wijmo.cloud/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.angular2.chart.analytics": "npm:@mescius/wijmo.angular2.chart.analytics/index.js", "@mescius/wijmo.angular2.chart.animation": "npm:@mescius/wijmo.angular2.chart.animation/index.js", "@mescius/wijmo.angular2.chart.annotation": "npm:@mescius/wijmo.angular2.chart.annotation/index.js", "@mescius/wijmo.angular2.chart.finance.analytics": "npm:@mescius/wijmo.angular2.chart.finance.analytics/index.js", "@mescius/wijmo.angular2.chart.finance": "npm:@mescius/wijmo.angular2.chart.finance/index.js", "@mescius/wijmo.angular2.chart.hierarchical": "npm:@mescius/wijmo.angular2.chart.hierarchical/index.js", "@mescius/wijmo.angular2.chart.interaction": "npm:@mescius/wijmo.angular2.chart.interaction/index.js", "@mescius/wijmo.angular2.chart.radar": "npm:@mescius/wijmo.angular2.chart.radar/index.js", '@mescius/wijmo.angular2.chart.map': 'npm:@mescius/wijmo.angular2.chart.map/index.js', "@mescius/wijmo.angular2.chart": "npm:@mescius/wijmo.angular2.chart/index.js", "@mescius/wijmo.angular2.core": "npm:@mescius/wijmo.angular2.core/index.js", "@mescius/wijmo.angular2.gauge": "npm:@mescius/wijmo.angular2.gauge/index.js", "@mescius/wijmo.angular2.grid.detail": "npm:@mescius/wijmo.angular2.grid.detail/index.js", "@mescius/wijmo.angular2.grid.filter": "npm:@mescius/wijmo.angular2.grid.filter/index.js", "@mescius/wijmo.angular2.grid.grouppanel": "npm:@mescius/wijmo.angular2.grid.grouppanel/index.js", "@mescius/wijmo.angular2.grid.search": "npm:@mescius/wijmo.angular2.grid.search/index.js", "@mescius/wijmo.angular2.grid.multirow": "npm:@mescius/wijmo.angular2.grid.multirow/index.js", "@mescius/wijmo.angular2.grid.sheet": "npm:@mescius/wijmo.angular2.grid.sheet/index.js", '@mescius/wijmo.angular2.grid.transposed': 'npm:@mescius/wijmo.angular2.grid.transposed/index.js', '@mescius/wijmo.angular2.grid.transposedmultirow': 'npm:@mescius/wijmo.angular2.grid.transposedmultirow/index.js', "@mescius/wijmo.angular2.grid": "npm:@mescius/wijmo.angular2.grid/index.js", "@mescius/wijmo.angular2.input": "npm:@mescius/wijmo.angular2.input/index.js", "@mescius/wijmo.angular2.olap": "npm:@mescius/wijmo.angular2.olap/index.js", "@mescius/wijmo.angular2.viewer": "npm:@mescius/wijmo.angular2.viewer/index.js", "@mescius/wijmo.angular2.nav": "npm:@mescius/wijmo.angular2.nav/index.js", "@mescius/wijmo.angular2.directivebase": "npm:@mescius/wijmo.angular2.directivebase/index.js", '@mescius/wijmo.angular2.barcode.common': 'npm:@mescius/wijmo.angular2.barcode.common/index.js', '@mescius/wijmo.angular2.barcode.composite': 'npm:@mescius/wijmo.angular2.barcode.composite/index.js', '@mescius/wijmo.angular2.barcode.specialized': 'npm:@mescius/wijmo.angular2.barcode.specialized/index.js', 'bootstrap.css': 'npm:bootstrap/dist/css/bootstrap.min.css', 'jszip': 'https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js', '@angular/core': 'npm:@angular/core/fesm2022/core.mjs', '@angular/core/primitives/signals': 'npm:@angular/core/fesm2022/primitives/signals.mjs', '@angular/core/primitives/event-dispatch': 'npm:@angular/core/fesm2022/primitives/event-dispatch.mjs', '@angular/common': 'npm:@angular/common/fesm2022/common.mjs', '@angular/common/http': 'npm:@angular/common/fesm2022/http.mjs', '@angular/compiler': 'npm:@angular/compiler/fesm2022/compiler.mjs', '@angular/platform-browser': 'npm:@angular/platform-browser/fesm2022/platform-browser.mjs', '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/fesm2022/platform-browser-dynamic.mjs', '@angular/http': 'npm:@angular/http/fesm2022/http.mjs', '@angular/router': 'npm:@angular/router/fesm2022/router.mjs', '@angular/forms': 'npm:@angular/forms/fesm2022/forms.mjs', }, // packages tells the System loader how to load when no filename and/or no extension packages: { "./src": { defaultExtension: 'ts' }, "node_modules": { defaultExtension: 'js' }, wijmo: { defaultExtension: 'js', } } }); })(this);