Cell Templates (Angular)

Wijmo interops for popular frameworks allow you to define custom content for MultiRow cells declaratively, by using each frameworks' own template markup in conjunction with Wijmo's MultiRowCellTemplate component.

Such templates may include arbitrary components and HTML elements, with property and event bindings. All types of grid cells can be defined using templates (data cells, header cells, editors, etc).

This sample shows a grid with the templates for all cell types. The templates can be dynamically enabled or disabled by toggling the checkboxes.

Learn about MultiRow | MultiRow API Reference

This example uses Angular.

import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './styles.css'; // import '@angular/compiler'; 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 { WjInputModule } from '@grapecity/wijmo.angular2.input'; import { WjGridMultirowModule } from '@grapecity/wijmo.angular2.grid.multirow'; import { DataService } from './app.data'; // @Component({ selector: 'app-component', templateUrl: 'src/app.component.html' }) export class AppComponent { countries: string[]; data: wjcCore.CollectionView; customTopLeft = true; customRowHeader = true; customRowHeaderEdit = true; customCell = true; customCellEdit = true; customColumnHeader = true; customGroupHeader = true; customGroup = true; highlightDownloads = true; // @ViewChild('grid', { static: true }) grid: wjcGrid.FlexGrid; // constructor( @Inject(DataService) dataSvc: DataService) { this.countries = dataSvc.getCountries(); this.data = dataSvc.getCv(dataSvc.getData()); } } // @NgModule({ imports: [WjInputModule, WjGridMultirowModule, 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>Cell Templates</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="node_modules/systemjs/dist/system.src.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"> <p> Use an <b>ng-template</b> element with the <b>wjMultiRowCellTemplate</b> directive to define a cell template. The content of the <b>ng-template</b> element defines the cell content. The <b>cellType</b> property specifies the type of the cells represented by the template. The <b>cell</b> local template variable contains an object with cell specific data, including the data item (<b>item</b>), row (<b>row</b>) and column (<b>col</b>) that the cell represents. </p> <p> Note that column-specific templates should be defined as children of the corresponding <b>wj-multi-row-cell</b> component, while the others are defined under the <b>wj-multi-row</b> element. </p> <wj-multi-row #mr [itemsSource]="data" [multiRowGroupHeaders]="true"> <ng-template wjMultiRowCellTemplate [cellType]="'TopLeft'" *ngIf="customTopLeft"> № </ng-template> <ng-template wjMultiRowCellTemplate [cellType]="'RowHeader'" *ngIf="customRowHeader" let-cell="cell"> {{cell.row.index / mr.rowsPerItem + 1}} </ng-template> <ng-template wjMultiRowCellTemplate [cellType]="'RowHeaderEdit'" *ngIf="customRowHeaderEdit"> ... </ng-template> <wj-multi-row-cell-group header="Identity" > <wj-multi-row-cell binding='id' [header]="'ID'" > <ng-template wjMultiRowCellTemplate [cellType]="'ColumnHeader'" *ngIf="customColumnHeader"> <i>ID</i> </ng-template> </wj-multi-row-cell> <wj-multi-row-cell binding='date' [header]="'Date'" [colspan]="1" [width]="140"> <ng-template wjMultiRowCellTemplate [cellType]="'CellEdit'" *ngIf="customCellEdit" let-cell="cell"> <wj-input-date class="cell-editor" [(value)]="cell.value"></wj-input-date> </ng-template> </wj-multi-row-cell> </wj-multi-row-cell-group> <wj-multi-row-cell-group header="Statistics" [colspan]="2"> <wj-multi-row-cell header="Country" binding="country" [colspan]="2"> <ng-template wjMultiRowCellTemplate [cellType]="'ColumnHeader'" *ngIf="customColumnHeader"> <i>Country</i> </ng-template> <ng-template wjMultiRowCellTemplate [cellType]="'Cell'" *ngIf="customCell" let-cell="cell"> <img src="resources/{{cell.item.country}}.png" /> {{cell.item.country}} </ng-template> <ng-template wjMultiRowCellTemplate [cellType]="'CellEdit'" *ngIf="customCellEdit" let-cell="cell"> <wj-combo-box [itemsSource]="countries" class="cell-editor" [(selectedValue)]="cell.value" [isEditable]="false" [isRequired]="false" [placeholder]="'Select a Country'"> </wj-combo-box> </ng-template> <ng-template wjMultiRowCellTemplate [cellType]="'GroupHeader'" *ngIf="customGroupHeader" let-cell="cell"> <input type="checkbox" [(ngModel)]="cell.row.isCollapsed" /> {{cell.item.name}} ({{cell.item.items.length}} items) </ng-template> </wj-multi-row-cell> <wj-multi-row-cell header="Downloads" binding="downloads" [width]="170" [aggregate]="'Sum'"> <ng-template wjMultiRowCellTemplate [cellType]="'Cell'" *ngIf="customCell" let-cell="cell"> <span [ngStyle]="{color: highlightDownloads? (cell.item.downloads>10000 ?'green':'red'):''}" style="font-weight:700"> {{cell.item.downloads}} </span> </ng-template> <ng-template wjMultiRowCellTemplate [cellType]="'CellEdit'" *ngIf="customCellEdit" let-cell="cell"> <wj-input-number class="cell-editor" [(value)]="cell.value" [step]="1"></wj-input-number> </ng-template> <ng-template wjMultiRowCellTemplate [cellType]="'Group'" *ngIf="customGroup" let-cell="cell"> Downloads: {{cell.value | number:'1.0-0'}} </ng-template> </wj-multi-row-cell> <wj-multi-row-cell header="Sales" binding="sales" [width]="170" [aggregate]="'Sum'"> <ng-template wjMultiRowCellTemplate [cellType]="'Cell'" *ngIf="customCell" let-cell="cell"> <span [ngStyle]="{color: highlightDownloads? (cell.item.sales>3000 ?'green':'red'):''}" style="font-weight:700"> {{cell.item.sales}} </span> </ng-template> <ng-template wjMultiRowCellTemplate [cellType]="'CellEdit'" *ngIf="customCellEdit" let-cell="cell"> <wj-input-number class="cell-editor" [(value)]="cell.value" [step]="1"></wj-input-number> </ng-template> <ng-template wjMultiRowCellTemplate [cellType]="'Group'" *ngIf="customGroup" let-cell="cell"> Sales: {{cell.value | number:'1.2-2'}} </ng-template> </wj-multi-row-cell> </wj-multi-row-cell-group> </wj-multi-row> <div class="checkbox-list"> <div class="checkbox-list-title">Cell level templates:</div> <div class="checkbox-cell"> <label class="checkbox"> <input type="checkbox" [(ngModel)]="customCell" /> Cell </label> <label class="checkbox"> <input type="checkbox" [(ngModel)]="customCellEdit" /> CellEdit </label> </div> <div class="checkbox-cell"> <label class="checkbox"> <input type="checkbox" [(ngModel)]="customColumnHeader" /> ColumnHeader </label> </div> <div class="checkbox-cell"> <label class="checkbox"> <input type="checkbox" [(ngModel)]="customGroupHeader" /> GroupHeader </label> <label class="checkbox"> <input type="checkbox" [(ngModel)]="customGroup" /> Group </label> </div> <div class="checkbox-list-title">MultiRow level templates:</div> <div class="checkbox-cell"> <label class="checkbox"> <input type="checkbox" [(ngModel)]="customTopLeft" /> TopLeft </label> </div> <div class="checkbox-cell"> <label class="checkbox"> <input type="checkbox" [(ngModel)]="customRowHeader" /> RowHeader </label> <label class="checkbox"> <input type="checkbox" [(ngModel)]="customRowHeaderEdit" /> RowHeaderEdit </label> </div> </div> </div>
import { Injectable } from '@angular/core'; import * as wjcCore from '@grapecity/wijmo'; // @Injectable() export class DataService { // data used to generate random items getData(): any[] { var countries = this.getCountries(), data = []; for (var i = 0; i < 30; i++) { data.push({ id: i, date: new Date(2015, Math.floor(i / countries.length) % 12, (Math.floor(i / countries.length) + 1) % 28), country: countries[i % countries.length], countryMapped: i % countries.length, downloads: Math.round(Math.random() * 20000), sales: Math.round(Math.random() * 10000 * 100) / 100, expenses: Math.random() * 5000, checked: i % 9 == 0 }); } return data; } getCountries(): string[] { return 'US,Germany,UK,Japan,Italy,Greece'.split(','); } getCv(data: any[]): wjcCore.CollectionView { var dataCv = new wjcCore.CollectionView(data); dataCv.groupDescriptions.push(new wjcCore.PropertyGroupDescription('country')); return dataCv; } }
body { margin-bottom: 24px; } label { margin-right: 3px; } .checkbox-list { padding: 0 20px; } .checkbox-cell { display: table-cell; padding-right: 50px; } .checkbox-list .checkbox { /* width: 50%; */ /* float:left; */ /* width: 100px; */ margin: 10px 0 0 0; /* display: inline-block; */ } .checkbox-list-title { font-size: 18px; margin: 10px 0px 2px -20px; } .wj-flexgrid { max-height: 350px; max-width: 600px; margin: 10px 0; } .cell-editor { position: absolute; left: 0px; width: 100%; border-radius: 0px; margin: -4px 0 -3px 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' } }, paths: { // paths serve as alias 'npm:': '' }, packageConfigPaths: [ '/node_modules/*/package.json', "/node_modules/@angular/*/package.json", "/node_modules/@grapecity/*/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', '@grapecity/wijmo': 'npm:@grapecity/wijmo/index.js', '@grapecity/wijmo.input': 'npm:@grapecity/wijmo.input/index.js', '@grapecity/wijmo.styles': 'npm:@grapecity/wijmo.styles', '@grapecity/wijmo.cultures': 'npm:@grapecity/wijmo.cultures', '@grapecity/wijmo.chart': 'npm:@grapecity/wijmo.chart/index.js', '@grapecity/wijmo.chart.analytics': 'npm:@grapecity/wijmo.chart.analytics/index.js', '@grapecity/wijmo.chart.animation': 'npm:@grapecity/wijmo.chart.animation/index.js', '@grapecity/wijmo.chart.annotation': 'npm:@grapecity/wijmo.chart.annotation/index.js', '@grapecity/wijmo.chart.finance': 'npm:@grapecity/wijmo.chart.finance/index.js', '@grapecity/wijmo.chart.finance.analytics': 'npm:@grapecity/wijmo.chart.finance.analytics/index.js', '@grapecity/wijmo.chart.hierarchical': 'npm:@grapecity/wijmo.chart.hierarchical/index.js', '@grapecity/wijmo.chart.interaction': 'npm:@grapecity/wijmo.chart.interaction/index.js', '@grapecity/wijmo.chart.radar': 'npm:@grapecity/wijmo.chart.radar/index.js', '@grapecity/wijmo.chart.render': 'npm:@grapecity/wijmo.chart.render/index.js', '@grapecity/wijmo.chart.webgl': 'npm:@grapecity/wijmo.chart.webgl/index.js', '@grapecity/wijmo.chart.map': 'npm:@grapecity/wijmo.chart.map/index.js', '@grapecity/wijmo.gauge': 'npm:@grapecity/wijmo.gauge/index.js', '@grapecity/wijmo.grid': 'npm:@grapecity/wijmo.grid/index.js', '@grapecity/wijmo.grid.detail': 'npm:@grapecity/wijmo.grid.detail/index.js', '@grapecity/wijmo.grid.filter': 'npm:@grapecity/wijmo.grid.filter/index.js', '@grapecity/wijmo.grid.search': 'npm:@grapecity/wijmo.grid.search/index.js', '@grapecity/wijmo.grid.grouppanel': 'npm:@grapecity/wijmo.grid.grouppanel/index.js', '@grapecity/wijmo.grid.multirow': 'npm:@grapecity/wijmo.grid.multirow/index.js', '@grapecity/wijmo.grid.transposed': 'npm:@grapecity/wijmo.grid.transposed/index.js', '@grapecity/wijmo.grid.transposedmultirow': 'npm:@grapecity/wijmo.grid.transposedmultirow/index.js', '@grapecity/wijmo.grid.pdf': 'npm:@grapecity/wijmo.grid.pdf/index.js', '@grapecity/wijmo.grid.sheet': 'npm:@grapecity/wijmo.grid.sheet/index.js', '@grapecity/wijmo.grid.xlsx': 'npm:@grapecity/wijmo.grid.xlsx/index.js', '@grapecity/wijmo.grid.selector': 'npm:@grapecity/wijmo.grid.selector/index.js', '@grapecity/wijmo.grid.cellmaker': 'npm:@grapecity/wijmo.grid.cellmaker/index.js', '@grapecity/wijmo.nav': 'npm:@grapecity/wijmo.nav/index.js', '@grapecity/wijmo.odata': 'npm:@grapecity/wijmo.odata/index.js', '@grapecity/wijmo.olap': 'npm:@grapecity/wijmo.olap/index.js', '@grapecity/wijmo.rest': 'npm:@grapecity/wijmo.rest/index.js', '@grapecity/wijmo.pdf': 'npm:@grapecity/wijmo.pdf/index.js', '@grapecity/wijmo.pdf.security': 'npm:@grapecity/wijmo.pdf.security/index.js', '@grapecity/wijmo.viewer': 'npm:@grapecity/wijmo.viewer/index.js', '@grapecity/wijmo.xlsx': 'npm:@grapecity/wijmo.xlsx/index.js', '@grapecity/wijmo.undo': 'npm:@grapecity/wijmo.undo/index.js', '@grapecity/wijmo.interop.grid': 'npm:@grapecity/wijmo.interop.grid/index.js', '@grapecity/wijmo.touch': 'npm:@grapecity/wijmo.touch/index.js', '@grapecity/wijmo.cloud': 'npm:@grapecity/wijmo.cloud/index.js', '@grapecity/wijmo.barcode': 'npm:@grapecity/wijmo.barcode/index.js', '@grapecity/wijmo.barcode.common': 'npm:@grapecity/wijmo.barcode.common/index.js', '@grapecity/wijmo.barcode.composite': 'npm:@grapecity/wijmo.barcode.composite/index.js', '@grapecity/wijmo.barcode.specialized': 'npm:@grapecity/wijmo.barcode.specialized/index.js', "@grapecity/wijmo.angular2.chart.analytics": "npm:@grapecity/wijmo.angular2.chart.analytics/index.js", "@grapecity/wijmo.angular2.chart.animation": "npm:@grapecity/wijmo.angular2.chart.animation/index.js", "@grapecity/wijmo.angular2.chart.annotation": "npm:@grapecity/wijmo.angular2.chart.annotation/index.js", "@grapecity/wijmo.angular2.chart.finance.analytics": "npm:@grapecity/wijmo.angular2.chart.finance.analytics/index.js", "@grapecity/wijmo.angular2.chart.finance": "npm:@grapecity/wijmo.angular2.chart.finance/index.js", "@grapecity/wijmo.angular2.chart.hierarchical": "npm:@grapecity/wijmo.angular2.chart.hierarchical/index.js", "@grapecity/wijmo.angular2.chart.interaction": "npm:@grapecity/wijmo.angular2.chart.interaction/index.js", "@grapecity/wijmo.angular2.chart.radar": "npm:@grapecity/wijmo.angular2.chart.radar/index.js", '@grapecity/wijmo.angular2.chart.map': 'npm:@grapecity/wijmo.angular2.chart.map/index.js', "@grapecity/wijmo.angular2.chart": "npm:@grapecity/wijmo.angular2.chart/index.js", "@grapecity/wijmo.angular2.core": "npm:@grapecity/wijmo.angular2.core/index.js", "@grapecity/wijmo.angular2.gauge": "npm:@grapecity/wijmo.angular2.gauge/index.js", "@grapecity/wijmo.angular2.grid.detail": "npm:@grapecity/wijmo.angular2.grid.detail/index.js", "@grapecity/wijmo.angular2.grid.filter": "npm:@grapecity/wijmo.angular2.grid.filter/index.js", "@grapecity/wijmo.angular2.grid.grouppanel": "npm:@grapecity/wijmo.angular2.grid.grouppanel/index.js", "@grapecity/wijmo.angular2.grid.search": "npm:@grapecity/wijmo.angular2.grid.search/index.js", "@grapecity/wijmo.angular2.grid.multirow": "npm:@grapecity/wijmo.angular2.grid.multirow/index.js", "@grapecity/wijmo.angular2.grid.sheet": "npm:@grapecity/wijmo.angular2.grid.sheet/index.js", '@grapecity/wijmo.angular2.grid.transposed': 'npm:@grapecity/wijmo.angular2.grid.transposed/index.js', '@grapecity/wijmo.angular2.grid.transposedmultirow': 'npm:@grapecity/wijmo.angular2.grid.transposedmultirow/index.js', "@grapecity/wijmo.angular2.grid": "npm:@grapecity/wijmo.angular2.grid/index.js", "@grapecity/wijmo.angular2.input": "npm:@grapecity/wijmo.angular2.input/index.js", "@grapecity/wijmo.angular2.olap": "npm:@grapecity/wijmo.angular2.olap/index.js", "@grapecity/wijmo.angular2.viewer": "npm:@grapecity/wijmo.angular2.viewer/index.js", "@grapecity/wijmo.angular2.nav": "npm:@grapecity/wijmo.angular2.nav/index.js", "@grapecity/wijmo.angular2.directivebase": "npm:@grapecity/wijmo.angular2.directivebase/index.js", '@grapecity/wijmo.angular2.barcode.common': 'npm:@grapecity/wijmo.angular2.barcode.common/index.js', '@grapecity/wijmo.angular2.barcode.composite': 'npm:@grapecity/wijmo.angular2.barcode.composite/index.js', '@grapecity/wijmo.angular2.barcode.specialized': 'npm:@grapecity/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/common/http": "https://cdn.jsdelivr.net/npm/@angular/common@16.2.6/fesm2022/http.mjs", "@angular/core": "https://cdn.jsdelivr.net/npm/@angular/core@16.2.6/fesm2022/core.mjs", "@angular/platform-browser": "https://cdn.jsdelivr.net/npm/@angular/platform-browser@16.2.6/fesm2022/platform-browser.mjs", "@angular/common": "https://cdn.jsdelivr.net/npm/@angular/common@16.2.6/fesm2022/common.mjs", "@angular/compiler": "https://cdn.jsdelivr.net/npm/@angular/compiler@16.2.6/fesm2022/compiler.mjs", "@angular/forms": "https://cdn.jsdelivr.net/npm/@angular/forms@16.2.6/fesm2022/forms.mjs", "@angular/localize": "https://cdn.jsdelivr.net/npm/@angular/localize@16.2.6/fesm2022/localize.mjs", "@angular/platform-browser-dynamic": "https://cdn.jsdelivr.net/npm/@angular/platform-browser-dynamic@16.2.6/fesm2022/platform-browser-dynamic.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);