CellTemplate 101

Getting Started

Wijmo provides a WjFlexGridCellTemplate directive for Angular 2 that allows you to define a template for any type of FlexGrid cell.

This example shows a FlexGrid that includes all of the cell types available, and allows you to selectively apply specific cell templates to the control. Each template applies to every cell of its specified type within the control. Clear a checkbox to see the template removed from all instances of that cell type.

Note that in order to see the change for the CellEdit cell type, you must first double-click inside a cell to put it in edit mode. To see the change for the RowHeaderEdit cell type, put any cell into edit mode, and look at the RowHeader cell for that row.

<wj-flex-grid [itemsSource]="data1" [allowSorting]="false" [deferResizing]="true"> <template wjFlexGridCellTemplate [cellType]="'TopLeft'" *ngIf="customTopLeft"> № </template> <template wjFlexGridCellTemplate [cellType]="'BottomLeft'" *ngIf="customBottomLeft"> &#931; </template> <template wjFlexGridCellTemplate [cellType]="'RowHeader'" *ngIf="customRowHeader" let-cell="cell"> {​{cell.row.index}​} </template> <template wjFlexGridCellTemplate [cellType]="'RowHeaderEdit'" *ngIf="customRowHeaderEdit"> ... </template> <wj-flex-grid-column header="Country" binding="country" width="*"> <template wjFlexGridCellTemplate [cellType]="'Cell'" *ngIf="customCell" let-item="item"> <img src="resources/{​{item.country}​}.png" /> {​{item.country}​} </template> <template wjFlexGridCellTemplate [cellType]="'CellEdit'" *ngIf="customCellEdit" let-cell="cell"> <wj-combo-box [itemsSource]="countries" [(selectedValue)]="cell.value" [isEditable]="false"></wj-combo-box> </template> <template wjFlexGridCellTemplate [cellType]="'GroupHeader'" *ngIf="customGroupHeader" let-item="item" let-cell="cell"> <input type="checkbox" [(ngModel)]="cell.row.isCollapsed" /> {​{item.name}​} ({​{item.items.length}​} items) </template> </wj-flex-grid-column> <wj-flex-grid-column header="Downloads" binding="downloads" [width]="170" [aggregate]="'Sum'"> <template wjFlexGridCellTemplate [cellType]="'ColumnHeader'" *ngIf="customColumnHeader"> <input type="checkbox" [(ngModel)]="uiCtx.highlightDownloads" /> Downloads </template> <template wjFlexGridCellTemplate [cellType]="'Cell'" *ngIf="customCell" let-item="item"> <span [ngStyle]="{color: uiCtx.highlightDownloads? (item.downloads>10000 ?'green':'red'):''}" style="font-weight:700"> {​{item.downloads}​} </span> </template> <template wjFlexGridCellTemplate [cellType]="'CellEdit'" *ngIf="customCell" let-cell="cell"> <wj-input-number [(value)]="cell.value" [step]="1"></wj-input-number> </template> <template wjFlexGridCellTemplate [cellType]="'Group'" *ngIf="customGroup" let-cell="cell"> Sum = {​{cell.value | number:'1.0-0'}​} </template> <template wjFlexGridCellTemplate [cellType]="'ColumnFooter'" *ngIf="customColumnFooter" let-cell="cell"> Sum: {​{cell.value | number:'1.0-0'}​} </template> </wj-flex-grid-column> </wj-flex-grid> <div class="checkbox-list"> <label class="checkbox"> <input type="checkbox" [(ngModel)]="customTopLeft" /> TopLeft </label> <label class="checkbox"> <input type="checkbox" [(ngModel)]="customRowHeader" /> RowHeader </label> <label class="checkbox"> <input type="checkbox" [(ngModel)]="customRowHeaderEdit" /> RowHeaderEdit </label> <label class="checkbox"> <input type="checkbox" [(ngModel)]="customCell" /> Cell </label> <label class="checkbox"> <input type="checkbox" [(ngModel)]="customCellEdit" /> CellEdit </label> <label class="checkbox"> <input type="checkbox" [(ngModel)]="customColumnHeader" /> ColumnHeader </label> <label class="checkbox"> <input type="checkbox" [(ngModel)]="customGroupHeader" /> GroupHeader </label> <label class="checkbox"> <input type="checkbox" [(ngModel)]="customGroup" /> Group </label> <label class="checkbox"> <input type="checkbox" [(ngModel)]="customColumnFooter" /> ColumnFooter </label> <label class="checkbox"> <input type="checkbox" [(ngModel)]="customBottomLeft" /> BottomLeft </label> </div>
import * as wjcCore from 'wijmo/wijmo'; 'use strict'; import { Injectable } from '@angular/core'; // Common data service @Injectable() export class DataSvc { // data used to generate random items getData(): any[] { var countries = 'US,Germany,UK,Japan,Italy,Greece'.split(','), 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; } getCv(data: any[]): wjcCore.CollectionView { var dataCv = new wijmo.collections.CollectionView(data); dataCv.sortDescriptions.push(new wijmo.collections.SortDescription('date', true)); dataCv.groupDescriptions.push(new wijmo.collections.PropertyGroupDescription('country')); return dataCv; } } // Angular import * as wjcCore from 'wijmo/wijmo'; import * as wjcGrid from 'wijmo/wijmo.grid'; import { Component, EventEmitter, Input, Inject, enableProdMode, AfterViewInit, NgModule, ViewChild } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { CommonModule } from '@angular/common'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { BrowserModule } from '@angular/platform-browser'; import { WjCoreModule } from 'wijmo/wijmo.angular2.core'; import { WjGridModule } from 'wijmo/wijmo.angular2.grid'; import { WjChartModule } from 'wijmo/wijmo.angular2.chart'; import { WjInputModule } from 'wijmo/wijmo.angular2.input'; import { TabsModule } from './components/AppTab'; import { DataSvc } from './services/DataSvc'; import { CountryGroupHeaderTemplate } from './CellTemplates/CountryGroupHeaderTemplate'; import { StatGroupTemplate } from './CellTemplates/StatGroupTemplate'; import { StatHeaderTemplate } from './CellTemplates/StatHeaderTemplate'; 'use strict'; // The application root component. @Component({ selector: 'app-cmp', templateUrl: 'src/app.html' }) export class AppCmp { countries = 'US,Germany,UK,Japan,Italy,Greece'.split(','); data1: wjcCore.CollectionView; customTopLeft = true; customRowHeader = true; customRowHeaderEdit = true; customCell = true; customCellEdit = true; customColumnHeader = true; customGroupHeader = true; customGroup = true; customColumnFooter = true; customBottomLeft = true; uiCtx = { highlightDownloads: true }; @ViewChild('flex1') flex1: wjcGrid.FlexGrid; protected dataSvc: DataSvc; constructor( @Inject(DataSvc) dataSvc: DataSvc) { this.dataSvc = dataSvc; var data = dataSvc.getData(); this.data1 = dataSvc.getCv(data); } ngAfterViewInit() { if (this.flex1) { this.flex1.columnFooters.rows.push(new wjcGrid.GroupRow()); } } } @NgModule({ imports: [WjCoreModule, WjInputModule, WjGridModule, WjChartModule, BrowserModule, FormsModule, TabsModule], declarations: [CountryGroupHeaderTemplate, StatGroupTemplate, StatHeaderTemplate, AppCmp], entryComponents: [CountryGroupHeaderTemplate, StatGroupTemplate, StatHeaderTemplate], providers: [DataSvc], bootstrap: [AppCmp] }) export class AppModule { }

Result (live):

Conditional templates

This sample demonstrates cell templates with conditional content controlled by the Angular 2 ngIf directive. It is based on the same CollectionView data source as the previous example, grouped on the Country column, but this one appears like a summary report. It shows only group rows with a white background. (The background color is set in the CSS tab.) There are no visible detail rows in this grid.

The first Country column shows GroupHeader cells that are customized to show country flags. The Downloads column shows Group cells with a nested WjFlexGrid or WjFlexChart components bound to the group’s child items ([itemsSource]="item.items"). This allows us to show statistical data for the group, either as a chart or as a table. The customized Downloads column’s template adds a ComboBox that allows the user to choose how to represent the data.

The ngIf attribute on the WjFlexGrid and WjFlexChart components is bound to the value selected in the ComboBox, and controls which one appears in the group cell.

<wj-flex-grid #flex2 [itemsSource]="data2" [allowSorting]="false" (initialized)="flex2.collapseGroupsToLevel(0)" style="height:300px" [selectionMode]="'None'" [allowDragging]="'None'" [deferResizing]="true"> <wj-flex-grid-column header="Country" binding="country"> <template wjFlexGridCellTemplate [cellType]="'GroupHeader'" let-item="item" > <img src="resources/{​{item.name}​}.png" /> {​{item.name}​} </template> </wj-flex-grid-column> <wj-flex-grid-column header="Downloads" binding="downloads" width="*" [aggregate]="'Sum'" [align]="'center'"> <template wjFlexGridCellTemplate [cellType]="'ColumnHeader'" let-item="item" let-cell="cell"> {​{cell.col.header}​}: <wj-combo-box [itemsSource]="['Chart', 'Table']" [(text)]="uiCtx.reportType" style="width:100px;font-weight:400" [isEditable]="false"> </wj-combo-box> </template> <template wjFlexGridCellTemplate [cellType]="'Group'" let-item="item" let-cell="cell"> <div style="font-size:small;text-align:center"> {​{uiCtx.reportType}​} <wj-flex-grid *ngIf="uiCtx.reportType == 'Table'" [itemsSource]="item.items" [isReadOnly]="false" [headersVisibility]="'None'" [selectionMode]="'Cell'" style="height:140px;width:200px"> <wj-flex-grid-column binding="date" width="*"> </wj-flex-grid-column> <wj-flex-grid-column [binding]="cell.col.binding" width="*"> </wj-flex-grid-column> </wj-flex-grid> <wj-flex-chart *ngIf="uiCtx.reportType == 'Chart'" style="height:140px;width:200px;display:inline-block" [itemsSource]="item.items" binding="date" [chartType]="'Column'" [plotMargin]="5"> <wj-flex-chart-legend [position]="'None'"></wj-flex-chart-legend> <wj-flex-chart-axis [wjProperty]="'axisX'" [axisLine]="false" [labels]="false"> </wj-flex-chart-axis> <wj-flex-chart-axis [wjProperty]="'axisY'" [axisLine]="false" [labels]="false"> </wj-flex-chart-axis> <wj-flex-chart-series binding="{​{cell.col.binding}​}"></wj-flex-chart-series> </wj-flex-chart> </div> </template> </wj-flex-grid-column> </wj-flex-grid>
export class AppCmp implements AfterViewInit { countries = 'US,Germany,UK,Japan,Italy,Greece'.split(','); data2: wjcCore.CollectionView; uiCtx = { reportType: 'Chart' }; protected dataSvc: DataSvc; @ViewChild('flex2') flex2: wjcGrid.FlexGrid; constructor( @Inject(DataSvc) dataSvc: DataSvc) { this.dataSvc = dataSvc; var data = dataSvc.getData(); this.data2 = dataSvc.getCv(data); } ngAfterViewInit() { if (this.flex2) { this.flex2.collapseGroupsToLevel(0); } } }
/* Provide group rows with a white background */ .conditional .wj-flexgrid .wj-group { background: #fff; }

Result (live):

Dynamic columns with templates

This example is a variation of the previous example, but the inclusion and settings of statistical data columns in this grid is defined as an array in the component. The wj-flex-grid-column component is bound to this array via the Angular 2 ngFor directive. Each column settings object includes columnHeaderTemplate and groupTemplate properties containing template component for the cells.

This content is included in the wjFlexGridCellTemplate directives using the wj-component-loader component.

Each column settings object also has an isAvailable property indicating whether the column is included in the FlexGrid. The inclusion is controlled by the ngIf directive on the wj-flex-grid-column component. You can change this value for each column settings object using the Wijmo ListBox control with checkboxes, which is bound to the column settings array.

The Country column is defined statically in the markup, and uses the CountryGroupHeaderTemplate component as its GroupHeader cell template.

<wj-flex-grid #flex3 [itemsSource]="data3" [allowSorting]="false" style="height:300px" [selectionMode]="'None'" [allowDragging]="'None'" [deferResizing]="true"> <wj-flex-grid-column header="Country" binding="country"> <template wjFlexGridCellTemplate cellType="GroupHeader" let-item="item"> <wj-component-loader [component]="countryGroupHeaderTemplate" [properties]="{item:item}"></wj-component-loader> </template> </wj-flex-grid-column> <template ngFor let-colDef [ngForOf]="statisticsColumns"> <wj-flex-grid-column *ngIf="colDef.isAvailable" [header]="colDef.header" [binding]="colDef.binding" [width]="colDef.width" [format]="colDef.format" [aggregate]="'Sum'" [align]="colDef.align"> <template wjFlexGridCellTemplate cellType="ColumnHeader" *ngIf="colDef.columnHeaderTemplate" let-cell="cell"> <wj-component-loader [component]="colDef.columnHeaderTemplate" [properties]="{cell:cell, colDef: colDef}"></wj-component-loader> </template> <template wjFlexGridCellTemplate cellType="Group" *ngIf="colDef.groupTemplate" let-cell="cell"> <wj-component-loader [component]="colDef.groupTemplate" [properties]="{cell:cell, colDef:colDef}"></wj-component-loader> </template> </wj-flex-grid-column> </template> </wj-flex-grid> <div style="margin:5px 0 5px"><b>Show statistics for:</b></div> <wj-list-box class="checkable-listbox" style="min-width:150px" [itemsSource]="statisticsColumns" displayMemberPath="header" checkedMemberPath="isAvailable"> </wj-list-box>
export class AppCmp implements AfterViewInit { countries = 'US,Germany,UK,Japan,Italy,Greece'.split(','); data3: wjcCore.CollectionView; statisticsColumns = [ { binding: 'downloads', header: 'Downloads', width: 230, align: 'center', format: 'N0', columnHeaderTemplateUrl: StatHeaderTemplate, groupTemplateUrl: StatGroupTemplate, reportType: 'Chart', isAvailable: true }, { binding: 'sales', header: 'Sales', width: 230, align: 'center', format: 'N2', columnHeaderTemplateUrl: StatHeaderTemplate, groupTemplateUrl: StatGroupTemplate, reportType: 'Chart', isAvailable: false }, { binding: 'expenses', header: 'Expenses', width: 230, align: 'center', format: 'N2', columnHeaderTemplateUrl: StatHeaderTemplate, groupTemplateUrl: StatGroupTemplate, reportType: 'Table', isAvailable: true }]; uiCtx = { reportType: 'Chart' }; countryGroupHeaderTemplate = CountryGroupHeaderTemplate; protected dataSvc: DataSvc; @ViewChild('flex3') flex3: wjcGrid.FlexGrid; constructor( @Inject(DataSvc) dataSvc: DataSvc) { this.dataSvc = dataSvc; var data = dataSvc.getData(); this.data3 = dataSvc.getCv(data); } ngAfterViewInit() { if (this.flex3) { this._dynaColumnsFlexInit(this.flex3); } } private _dynaColumnsFlexInit(flex: wjcGrid.FlexGrid) { flex.collapseGroupsToLevel(0); flex.columnHeaders.rows.defaultSize = 36; flex.cells.rows.defaultSize = 156; } } @Component({ selector: 'country-group-header-template', templateUrl: 'src/CellTemplates/countryGroupHeaderTemplate.html' }) export class CountryGroupHeaderTemplate { item: any; constructor() { } } @Component({ selector: 'column-header-template', templateUrl: 'src/CellTemplates/statHeaderTemplate.html' }) export class StatHeaderTemplate { cell: any; colDef: any; constructor() { } } @Component({ selector: 'expence-cell-edit-cmp', templateUrl: 'src/CellTemplates/statGroupTemplate.html' }) export class StatGroupTemplate { cell: any; colDef: any; constructor() { } }
{​{cell.col.header}​}: <wj-combo-box [itemsSource]="['Chart', 'Table']" [(selectedValue)]="colDef.reportType" style="width:100px;font-weight:400" [isEditable]="false"> </wj-combo-box>
<div style="font-size:small;text-align:center"> <wj-flex-grid *ngIf="colDef.reportType == 'Table'" [itemsSource]="cell.item.items" [isReadOnly]="false" [headersVisibility]="'None'" [selectionMode]="'Cell'" style="height:140px;width:200px"> <wj-flex-grid-column binding="date" [width]="'*'"> </wj-flex-grid-column> <wj-flex-grid-column [binding]="cell.col.binding" [width]="'*'"> </wj-flex-grid-column> </wj-flex-grid> <wj-flex-pie *ngIf="colDef.reportType == 'Chart'" [itemsSource]="cell.iitem.items" [binding]="cell.col.binding" tooltipContent="<b>{value:{​{cell.col.format}​}}</b><br/>{date:MMM yyyy}" style="height:140px;width:140px;display:inline-block;font-size:9px"> <wj-flex-chart-legend [position]="'None'"></wj-flex-chart-legend> <wj-flex-pie-data-label [content]="'{date:MMM}'" [position]="'Inside'"> </wj-flex-pie-data-label> </wj-flex-pie> </div>
<img src="resources/{​{item.name}​}.png" /> {​{item.name}​}
/* Provide group rows with a white background */ .conditional .wj-flexgrid .wj-group { background: #fff; } /* Remove highlighting of a selected item in ListBox */ .checkable-listbox .wj-state-selected { background-color: white; color: black; }

Result (live):

Show statistics for: