Paging (Angular)

The MultiRow control supports paging through the IPagedCollectionView interface, which is nearly identical to the one in .NET.

To enable paging, set the IPagedCollectionView.pageSize property to the number of items you want to display on each page, and provide a UI for navigating the pages.

Learn about MultiRow | MultiRow API Reference

This example uses Angular.

import 'bootstrap.css'; import '@mescius/wijmo.styles/wijmo.css'; import './styles.css'; // import * as wjCore from '@mescius/wijmo'; import '@angular/compiler'; import { Component, Inject, enableProdMode, AfterViewInit, ɵresolveComponentResources } from '@angular/core'; import { BrowserModule, bootstrapApplication } from '@angular/platform-browser'; import { WjGridMultirowModule } from '@mescius/wijmo.angular2.grid.multirow'; import { DataService } from './app.data'; // @Component({ standalone: true, providers: [DataService], imports: [WjGridMultirowModule, BrowserModule], selector: 'app-component', templateUrl: 'src/app.component.html', }) export class AppComponent implements AfterViewInit { pagedOrders: wjCore.CollectionView; layoutDefinition: any; pageText: string; // DataSvc will be passed by derived classes constructor(@Inject(DataService) private dataService: DataService) { const data = dataService.getData(); this.pagedOrders = data.pagedOrders; this.layoutDefinition = data.ldThreeLines; } // ngAfterViewInit() { this._updatePageText(); this.pagedOrders.collectionChanged.addHandler(() => { this._updatePageText(); }); this.pagedOrders.pageChanged.addHandler(() => { this._updatePageText(); }); } // onGotoPageClick(command: string) { if (command === 'first') { this.pagedOrders.moveToFirstPage(); } else if (command === 'previous') { this.pagedOrders.moveToPreviousPage(); } else if (command === 'next') { this.pagedOrders.moveToNextPage(); } else if (command === 'last') { this.pagedOrders.moveToLastPage(); } } // private _updatePageText() { this.pageText = wjCore.format('{index:n0} / {count:n0}', { index: this.pagedOrders.pageIndex + 1, count: this.pagedOrders.pageCount, }); } } //\\ // 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 MultiRow Paging</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"> <wj-multi-row [itemsSource]="pagedOrders" [layoutDefinition]="layoutDefinition"></wj-multi-row> <div class="btn-group"> <button type="button" class="btn" (click)="onGotoPageClick('first')" > <span class="glyphicon glyphicon-fast-backward"></span> </button> <button type="button" class="btn" (click)="onGotoPageClick('previous')" > <span class="glyphicon glyphicon-step-backward"></span> </button> <button type="button" class="btn" [innerHTML]="pageText" disabled style="width:100px"></button> <button type="button" class="btn" (click)="onGotoPageClick('next')" > <span class="glyphicon glyphicon-step-forward"></span> </button> <button type="button" class="btn" (click)="onGotoPageClick('last')" > <span class="glyphicon glyphicon-fast-forward"></span> </button> </div> </div>
import { Injectable } from '@angular/core'; import * as wjCore from '@mescius/wijmo'; import * as wjGrid from '@mescius/wijmo.grid'; interface Cell { binding: string; header: string; cssClass?: string; format?: string; isReadOnly?: boolean; wordWrap?: boolean; width: number; } interface Line { Cells: Cell[]; header?: string; colspan?: number; } export interface AppData { orders: wjCore.CollectionView; groupedOrders: wjCore.CollectionView; pagedOrders: wjCore.CollectionView; addNewOrders: wjCore.CollectionView; ldOneLine: Cell[]; ldTwoLines: Line[]; ldThreeLines: Line[]; layoutDefs: wjCore.CollectionView; } @Injectable() export class DataService { getData(): AppData { // create some data let appData: any = {}, customers = [], firstNames = 'Aaron,Paul,John,Mark,Sue,Tom,Bill,Joe,Tony,Brad,Frank,Chris,Pat'.split(','), lastNames = 'Smith,Johnson,Richards,Bannon,Wong,Peters,White,Brown,Adams,Jennings'.split(','), cities = 'York,Paris,Rome,Cairo,Florence,Sidney,Hamburg,Vancouver'.split(','), states = 'SP,RS,RN,SC,CS,RT,BC'.split(','); for (let i = 0; i < 50; i++) { let first = firstNames[randBetween(0, firstNames.length - 1)], last = lastNames[randBetween(0, lastNames.length - 1)]; customers.push({ id: i, name: first + ' ' + last, address: randBetween(100, 10000) + ' ' + lastNames[randBetween(0, lastNames.length - 1)] + ' St.', city: cities[randBetween(0, cities.length - 1)], state: states[randBetween(0, states.length - 1)], zip: wjCore.format('{p1:d5}-{p2:d3}', { p1: randBetween(10000, 99999), p2: randBetween(100, 999) }), email: first + '.' + last + '@gmail.com', phone: wjCore.format('{p1:d3}-{p2:d4}', { p1: randBetween(100, 999), p2: randBetween(1000, 9999) }) }); } let cityMap = new wjGrid.DataMap(cities); let shippers = [ { id: 0, name: 'Speedy Express', email: 'speedy@gmail.com', phone: '431-3234', express: true }, { id: 1, name: 'Flash Delivery', email: 'flash@gmail.com', phone: '431-6563', express: true }, { id: 2, name: 'Logitrax', email: 'logitrax@gmail.com', phone: '431-3981', express: false }, { id: 3, name: 'Acme Inc', email: 'acme@gmail.com', phone: '431-3113', express: false } ]; let orders = []; let today = new Date(); for (let i = 0; i < 20; i++) { let shipped = wjCore.DateTime.addDays(today, -randBetween(1, 3000)); orders.push({ id: i, date: wjCore.DateTime.addDays(shipped, -randBetween(1, 5)), shippedDate: shipped, amount: randBetween(10000, 500000) / 100, customer: customers[randBetween(0, customers.length - 1)], shipper: shippers[randBetween(0, shippers.length - 1)] }); } function randBetween(min: number, max: number) { return Math.floor(Math.random() * (max - min + 1) + min); } // expose orders CollectionView to the app appData.orders = new wjCore.CollectionView(orders); // expose grouped orders CollectionView to the app appData.groupedOrders = new wjCore.CollectionView(orders, { groupDescriptions: [ 'customer.city' ] }); // expose paged orders CollectionView to the app appData.pagedOrders = new wjCore.CollectionView(orders, { pageSize: 4 }); // expose addNew oders CollectionView to the app appData.addNewOrders = new wjCore.CollectionView(orders, { newItemCreator: function () { return { // add empty customer and shipper objects to new orders customer: {}, shipper: {} } }, }); appData.addNewOrders.moveCurrentToLast(); // refresh views when data source changes let ordersRefreshing = false; appData.orders.collectionChanged.addHandler(function () { ordersRefreshing = true; if (!pagedOrdersRefreshing) { appData.pagedOrders.refresh(); } if (!groupedOrdersRefreshing) { appData.groupedOrders.refresh(); } if (!addNewOrdersRefreshing) { appData.addNewOrders.refresh(); } ordersRefreshing = false; }); // addNew orders let addNewOrdersRefreshing = false; appData.addNewOrders.collectionChanged.addHandler(function () { addNewOrdersRefreshing = true; if (!ordersRefreshing) { appData.orders.refresh(); } if (!pagedOrdersRefreshing) { appData.pagedOrders.refresh(); } if (!groupedOrdersRefreshing) { appData.groupedOrders.refresh(); } addNewOrdersRefreshing = false; }); // grouped orders let groupedOrdersRefreshing = false; appData.groupedOrders.collectionChanged.addHandler(function () { groupedOrdersRefreshing = true; if (!ordersRefreshing) { appData.orders.refresh(); } if (!pagedOrdersRefreshing) { appData.pagedOrders.refresh(); } if (!addNewOrdersRefreshing) { appData.addNewOrders.refresh(); } groupedOrdersRefreshing = false; }); // paged orders let pagedOrdersRefreshing = false; appData.pagedOrders.collectionChanged.addHandler(function () { pagedOrdersRefreshing = true; if (!ordersRefreshing) { appData.orders.refresh(); } if (!addNewOrdersRefreshing) { appData.addNewOrders.refresh(); } if (!groupedOrdersRefreshing) { appData.groupedOrders.refresh(); } pagedOrdersRefreshing = false; }); // sample layout definitions appData.ldOneLine = [ { cells: [{ binding: 'id', header: 'ID', cssClass: 'id', isReadOnly: true }] }, { cells: [{ binding: 'date', header: 'Ordered' }] }, { cells: [{ binding: 'shippedDate', header: 'Shipped' }] }, { cells: [{ binding: 'amount', header: 'Amount', format: 'c', cssClass: 'amount' }] }, { cells: [{ binding: 'customer.name', header: 'Customer' }] }, { cells: [{ binding: 'customer.address', header: 'Address', wordWrap: true }] }, { cells: [{ binding: 'customer.city', header: 'City', dataMap: cityMap }] }, { cells: [{ binding: 'customer.state', header: 'State', width: 45 }] }, { cells: [{ binding: 'customer.zip', header: 'Zip' }] }, { cells: [{ binding: 'customer.email', header: 'Customer Email', cssClass: 'email' }] }, { cells: [{ binding: 'customer.phone', header: 'Customer Phone' }] }, { cells: [{ binding: 'shipper.name', header: 'Shipper' }] }, { cells: [{ binding: 'shipper.email', header: 'Shipper Email', cssClass: 'email' }] }, { cells: [{ binding: 'shipper.phone', header: 'Shipper Phone' }] }, { cells: [{ binding: 'shipper.express', header: 'Express' }] } ]; appData.ldTwoLines = [ { header: 'Order', colspan: 2, cells: [ { binding: 'id', header: 'ID', cssClass: 'id', isReadOnly: true }, { binding: 'date', header: 'Ordered' }, { binding: 'amount', header: 'Amount', format: 'c', cssClass: 'amount' }, { binding: 'shippedDate', header: 'Shipped' } ] }, { header: 'Customer', colspan: 3, cells: [ { binding: 'customer.name', header: 'Name' }, { binding: 'customer.email', header: 'EMail', colspan: 2, cssClass: 'email' }, { binding: 'customer.address', header: 'Address' }, { binding: 'customer.city', header: 'City', dataMap: cityMap }, { binding: 'customer.state', header: 'State', width: 45 } ] }, { header: 'Shipper', cells: [ { binding: 'shipper.name', header: 'Shipper', colspan: 2 }, { binding: 'shipper.email', header: 'EMail', cssClass: 'email' }, { binding: 'shipper.express', header: 'Express' } ] } ]; appData.ldThreeLines = [ { header: 'Order', colspan: 2, cells: [ { binding: 'id', header: 'ID', colspan: 2, cssClass: 'id' }, { binding: 'amount', header: 'Amount', format: 'c', colspan: 2, cssClass: 'amount' }, { binding: 'date', header: 'Ordered' }, { binding: 'shippedDate', header: 'Shipped' } ] }, { header: 'Customer', colspan: 3, cells: [ { binding: 'customer.name', header: 'Name' }, { binding: 'customer.email', header: 'EMail', colspan: 2, cssClass: 'email' }, { binding: 'customer.address', header: 'Address', colspan: 2 }, { binding: 'customer.phone', header: 'Phone' }, { binding: 'customer.city', header: 'City', dataMap: cityMap }, { binding: 'customer.state', header: 'State', width: 45 }, { binding: 'customer.zip', header: 'Zip' }, ] }, { header: 'Shipper', cells: [ { binding: 'shipper.name', header: 'Shipper' }, { binding: 'shipper.email', header: 'EMail', cssClass: 'email' }, { binding: 'shipper.express', header: 'Express' } ] } ]; appData.layoutDefs = new wjCore.CollectionView([ { name: 'Traditional', description: 'Traditional grid view, with one row per record. The user must scroll horizontally to see the whole record.', def: appData.ldOneLine }, { name: 'Compact', description: 'This view uses two rows per record. The layout is divided into three groups: order, customer, and shipper', def: appData.ldTwoLines }, { name: 'Detailed', description: 'This view uses three rows per record. The layout is divided into three groups: order, customer, and shipper', def: appData.ldThreeLines } ]); return appData; } }
.wj-multirow { margin: 6px 0; max-height:800px }
(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/di': 'npm:@angular/core/fesm2022/primitives/di.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);