Cell Templates (Angular)

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

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 FlexGrid | FlexGrid API Reference

This example uses Angular.

import 'bootstrap.css'; import '@mescius/wijmo.styles/wijmo.css'; import './styles.css'; // import '@angular/compiler'; import { Component, Inject, enableProdMode, ViewChild, ɵresolveComponentResources } from '@angular/core'; import { BrowserModule, bootstrapApplication } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; // import * as wjcCore from '@mescius/wijmo'; import * as wjcGrid from '@mescius/wijmo.grid'; import { WjInputModule } from '@mescius/wijmo.angular2.input'; import { WjGridModule } from '@mescius/wijmo.angular2.grid'; import { DataService } from './app.data'; // @Component({ standalone: true, providers: [DataService], imports: [WjInputModule, WjGridModule, BrowserModule, FormsModule], 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; customColumnFooter = true; customBottomLeft = 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()); } // ngAfterViewInit() { if (this.grid) { this.grid.columnFooters.rows.push(new wjcGrid.GroupRow()); } } } // // 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>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="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"> <p> Use an <b>ng-template</b> element with the <b>wjFlexGridCellTemplate</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-flex-grid-column</b> component, while the others are defined under the <b>wj-flex-grid</b> element. </p> <wj-flex-grid #grid [itemsSource]="data" [allowSorting]="false" [autoSizeMode]="'Both'" [allowResizing]="'Both'" [deferResizing]="true"> <ng-template wjFlexGridCellTemplate [cellType]="'TopLeft'" *ngIf="customTopLeft"> № </ng-template> <ng-template wjFlexGridCellTemplate [cellType]="'BottomLeft'" *ngIf="customBottomLeft"> &#931; </ng-template> <ng-template wjFlexGridCellTemplate [cellType]="'RowHeader'" *ngIf="customRowHeader" let-cell="cell"> {{cell.row.index + 1}} </ng-template> <ng-template wjFlexGridCellTemplate [cellType]="'RowHeaderEdit'" *ngIf="customRowHeaderEdit"> ... </ng-template> <wj-flex-grid-column header="Country" binding="country" width="*"> <ng-template wjFlexGridCellTemplate [cellType]="'Cell'" *ngIf="customCell" let-cell="cell"> <img src="resources/{{cell.item.country}}.png" /> {{cell.item.country}} </ng-template> <ng-template wjFlexGridCellTemplate [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 wjFlexGridCellTemplate [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-flex-grid-column> <wj-flex-grid-column header="Downloads" binding="downloads" [width]="170" [aggregate]="'Sum'"> <ng-template wjFlexGridCellTemplate [cellType]="'ColumnHeader'" *ngIf="customColumnHeader"> <input type="checkbox" [(ngModel)]="highlightDownloads" /> Downloads </ng-template> <ng-template wjFlexGridCellTemplate [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 wjFlexGridCellTemplate [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 wjFlexGridCellTemplate [cellType]="'Group'" *ngIf="customGroup" let-cell="cell"> Sum = {{cell.value | number:'1.0-0'}} </ng-template> <ng-template wjFlexGridCellTemplate [cellType]="'ColumnFooter'" *ngIf="customColumnFooter" let-cell="cell"> Sum: {{cell.value | number:'1.0-0'}} </ng-template> </wj-flex-grid-column> </wj-flex-grid> <div class="checkbox-list"> <div class="checkbox-list-title">Column 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> <label class="checkbox"> <input type="checkbox" [(ngModel)]="customColumnFooter" /> ColumnFooter </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">Grid level templates:</div> <div class="checkbox-cell"> <label class="checkbox"> <input type="checkbox" [(ngModel)]="customTopLeft" /> TopLeft </label> <label class="checkbox"> <input type="checkbox" [(ngModel)]="customBottomLeft" /> BottomLeft </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 '@mescius/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.random() * 10000, 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.sortDescriptions.push(new wjcCore.SortDescription('date', true)); 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/@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.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/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);