CellTemplate 101

Getting Started

Wijmo provides a WjFlexGridCellTemplate directive for Angular 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.

HTML
<wj-flex-grid items-source="data1" initialized="addFooterRow(s)" allow-sorting="false" defer-resizing="true"> <wj-flex-grid-cell-template cell-type="TopLeft" ng-if="customTopLeft"> № </wj-flex-grid-cell-template> <wj-flex-grid-cell-template cell-type="BottomLeft" ng-if="customBottomLeft"> &#931; </wj-flex-grid-cell-template> <wj-flex-grid-cell-template cell-type="RowHeader" ng-if="customRowHeader"> {​{$row.index}} </wj-flex-grid-cell-template> <wj-flex-grid-cell-template cell-type="RowHeaderEdit" ng-if="customRowHeaderEdit"> ... </wj-flex-grid-cell-template> <wj-flex-grid-column header="Country" binding="country" width="*"> <wj-flex-grid-cell-template cell-type="Cell" ng-if="customCell"> <img ng-src="resources/{​{$item.country}}.png" /> {​{$item.country}} </wj-flex-grid-cell-template> <wj-flex-grid-cell-template cell-type="CellEdit" ng-if="customCellEdit"> <wj-combo-box items-source="countries" selected-value="$value" is-editable="false"></wj-combo-box> </wj-flex-grid-cell-template> <wj-flex-grid-cell-template cell-type="GroupHeader" ng-if="customGroupHeader"> <input type="checkbox" ng-model="$row.isCollapsed" /> {​{$item.name}} ({​{$item.items.length}} items) </wj-flex-grid-cell-template> </wj-flex-grid-column> <wj-flex-grid-column header="Downloads" binding="downloads" width="170" aggregate="Sum"> <wj-flex-grid-cell-template cell-type="ColumnHeader" ng-if="customColumnHeader"> <input type="checkbox" ng-model="uiCtx.highlightDownloads" /> Downloads </wj-flex-grid-cell-template> <wj-flex-grid-cell-template cell-type="Cell" ng-if="customCell"> <span ng-style="uiCtx.highlightDownloads && ($item.downloads > 10000 && {'color': 'green'} || {'color': 'red'})" style="font-weight:700"> {​{$item.downloads}} </span> </wj-flex-grid-cell-template> <wj-flex-grid-cell-template cell-type="CellEdit" ng-if="customCellEdit"> <wj-input-number value="$value" step="1"></wj-input-number> </wj-flex-grid-cell-template> <wj-flex-grid-cell-template cell-type="Group" ng-if="customGroup"> Sum = {​{$value | number:0}} </wj-flex-grid-cell-template> <wj-flex-grid-cell-template cell-type="ColumnFooter" ng-if="customColumnFooter"> Sum = {​{$value | number:0}} </wj-flex-grid-cell-template> </wj-flex-grid-column> </wj-flex-grid> <div class="checkbox-list"> <label class="checkbox"> <input type="checkbox" ng-model="customTopLeft" /> TopLeft </label> <label class="checkbox"> <input type="checkbox" ng-model="customRowHeader" /> RowHeader </label> <label class="checkbox"> <input type="checkbox" ng-model="customRowHeaderEdit" /> RowHeaderEdit </label> <label class="checkbox"> <input type="checkbox" ng-model="customCell" /> Cell </label> <label class="checkbox"> <input type="checkbox" ng-model="customCellEdit" /> CellEdit </label> <label class="checkbox"> <input type="checkbox" ng-model="customColumnHeader" /> ColumnHeader </label> <label class="checkbox"> <input type="checkbox" ng-model="customGroupHeader" /> GroupHeader </label> <label class="checkbox"> <input type="checkbox" ng-model="customGroup" /> Group </label> <label class="checkbox"> <input type="checkbox" ng-model="customColumnFooter" /> ColumnFooter </label> <label class="checkbox"> <input type="checkbox" ng-model="customBottomLeft" /> BottomLeft </label> </div>
JS
// create some random data 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 }); } var getCv = function (data) { 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; } $scope.data1 = getCv(data); $scope.countries = countries; $scope.customTopLeft = true; $scope.customRowHeader = true; $scope.customRowHeaderEdit = true; $scope.customCell = true; $scope.customCellEdit = true; $scope.customColumnHeader = true; $scope.customGroupHeader = true; $scope.customGroup = true; $scope.customColumnFooter = true; $scope.customBottomLeft = true; $scope.uiCtx = { highlightDownloads: true, }; $scope.addFooterRow = function(s) { s.columnFooters.rows.push(new wijmo.grid.GroupRow()); }

Result (live):

Σ {{$row.index}} ... {{$item.country}} {{$item.name}} ({{$item.items.length}} items) Downloads {{$item.downloads}} Sum = {{$value | number:0}} Sum: {{$value | number:0}}

Conditional templates

This sample demonstrates cell templates with conditional content controlled by the Angular ng-if 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 FlexGrid or FlexChart control bound to the group’s child items (items-source="$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 ng-if attribute on the FlexGrid and FlexChart directives is bound to the value selected in the ComboBox, and controls which one appears in the group cell.

HTML
<div class="col-md-6 conditional"> <wj-flex-grid items-source="data2" allow-sorting="false" initialized="s.collapseGroupsToLevel(0)" style="height:300px" selection-mode="None" allow-dragging="None" defer-resizing="true"> <wj-flex-grid-column header="Country" binding="country"> <wj-flex-grid-cell-template cell-type="GroupHeader"> <img ng-src="resources/{​{$item.name}}.png" /> {​{$item.name}} </wj-flex-grid-cell-template> </wj-flex-grid-column> <wj-flex-grid-column header="Downloads" binding="downloads" width="*" aggregate="Sum" align="center"> <wj-flex-grid-cell-template cell-type="ColumnHeader"> {​{$col.header}}: <wj-combo-box items-source="['Chart', 'Table']" selected-value="uiCtx.reportType" style="width:100px;font-weight:400" is-editable="false"> </wj-combo-box> </wj-flex-grid-cell-template> <wj-flex-grid-cell-template cell-type="Group"> <div style="font-size:small;text-align:center"> <wj-flex-grid ng-if="uiCtx.reportType == 'Table'" items-source="$item.items" is-read-only="false" headers-visibility="None" selection-mode="Cell" style="height:140px;width:200px"> <wj-flex-grid-column binding="date" width="*"> </wj-flex-grid-column> <wj-flex-grid-column binding="{​{$col.binding}}" width="*"> </wj-flex-grid-column> </wj-flex-grid> <wj-flex-chart ng-if="uiCtx.reportType == 'Chart'" style="height:140px;width:200px;display:inline-block" items-source="$item.items" binding-x="date" chart-type="Column" plot-margin="5"> <wj-flex-chart-legend position="None"> </wj-flex-chart-legend> <wj-flex-chart-axis wj-property="axisX" axis-line="false" labels="false"> </wj-flex-chart-axis> <wj-flex-chart-axis wj-property="axisY" axis-line="false" labels="false"> </wj-flex-chart-axis> <wj-flex-chart-series binding="{​{$col.binding}}"> </wj-flex-chart-series> </wj-flex-chart> </div> </wj-flex-grid-cell-template> </wj-flex-grid-column> </wj-flex-grid> </div>
JS
var getCv = function (data) { 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; } $scope.data2 = getCv(data);
CSS
/* Provide group rows with a white background */ .conditional .wj-flexgrid .wj-group { background: #fff; }

Result (live):

{{$item.name}} {{$col.header}}:

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 controller. The wj-flex-grid-column directive is bound to this array via the Angular ng-repeat directive. Each column settings object includes columnHeaderTemplateUrl and groupTemplateUrl properties containing paths to html files with cell template content for the cells.

This content is included in the wj-flex-grid-cell-template directives using the Angular ng-include directive.

Each column settings object also has an isAvailable property indicating whether the column is included in the FlexGrid. The inclusion is controlled by the ng-if attribute on the wj-flex-grid-column directive. 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 retrieves its GroupHeader cell template’s content from the countryGroupHeaderTemplate.html file.

HTML
<div class="col-md-6 conditional"> <wj-flex-grid items-source="data3" allow-sorting="false" initialized="dynaColumnsFlexInit(s)" style="height:300px" selection-mode="None" allow-dragging="None" defer-resizing="true"> <wj-flex-grid-column header="Country" binding="country"> <wj-flex-grid-cell-template cell-type="GroupHeader"> <ng-include src="'scripts/CellTemplates/countryGroupHeaderTemplate.html'"> </ng-include> </wj-flex-grid-cell-template> </wj-flex-grid-column> <!-- ng-init here creates the colCtx property with subproperties that are isolated on a column level, that is not visible to another columns but share data with all the cell templates defined for the column. --> <wj-flex-grid-column ng-repeat="col in statisticsColumns" ng-init="colCtx = { reportType: col.reportType || 'Chart' }" ng-if="col.isAvailable" header="{​{col.header}}" binding="{​{col.binding}}" width="{​{col.width}}" format="{​{col.format}}" aggregate="Sum" align="{​{col.align}}"> <wj-flex-grid-cell-template cell-type="ColumnHeader" ng-if="col.columnHeaderTemplateUrl"> <ng-include src="col.columnHeaderTemplateUrl"> </ng-include> </wj-flex-grid-cell-template> <wj-flex-grid-cell-template cell-type="Group" ng-if="col.groupTemplateUrl"> <ng-include src="col.groupTemplateUrl"> </ng-include> </wj-flex-grid-cell-template> </wj-flex-grid-column> </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" items-source="statisticsColumns" display-member-path="header" checked-member-path="isAvailable"> </wj-list-box> </div>
JS
var getCv = function (data) { 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; } $scope.data3 = getCv(data); $scope.statisticsColumns = [ { binding: 'downloads', header: 'Downloads', width: '230', align: 'center', format: 'N0', columnHeaderTemplateUrl: 'scripts/CellTemplates/statHeaderTemplate.html', groupTemplateUrl: 'scripts/CellTemplates/statGroupTemplate.html', reportType: 'Chart', isAvailable: true }, { binding: 'sales', header: 'Sales', width: '230', align: 'center', format: 'N2', columnHeaderTemplateUrl: 'scripts/CellTemplates/statHeaderTemplate.html', groupTemplateUrl: 'scripts/CellTemplates/statGroupTemplate.html', reportType: 'Chart', isAvailable: false }, { binding: 'expenses', header: 'Expenses', width: '230', align: 'center', format: 'N2', columnHeaderTemplateUrl: 'scripts/CellTemplates/statHeaderTemplate.html', groupTemplateUrl: 'scripts/CellTemplates/statGroupTemplate.html', reportType: 'Table', isAvailable: true }, ]; $scope.dynaColumnsFlexInit = function (flex) { flex.collapseGroupsToLevel(0); flex.columnHeaders.rows.defaultSize = 36; flex.cells.rows.defaultSize = 156; }
statHeaderTemplate.html
{​{$col.header}}: <wj-combo-box items-source="['Chart', 'Table']" selected-value="colCtx.reportType" style="width:100px;font-weight:400" is-editable="false"> </wj-combo-box>
statGroupTemplate.html
<div style="font-size:small;text-align:center"> <wj-flex-grid ng-if="colCtx.reportType == 'Table'" items-source="$item.items" is-read-only="false" headers-visibility="None" selection-mode="Cell" format="{​{$col.format}}" style="height:140px;width:200px"> <wj-flex-grid-column binding="date" width="*"> </wj-flex-grid-column> <wj-flex-grid-column binding="{​{$col.binding}}" width="*"> </wj-flex-grid-column> </wj-flex-grid> <wj-flex-pie ng-if="colCtx.reportType == 'Chart'" items-source="$item.items" binding="{​{$col.binding}}" tooltip-content="<b>{value:{​{$col.format}}}</b><br/>{date:MMM yyyy}" style="height:140px;width:140px;display:inline-block"> <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>
countryGroupHeaderTemplate.html
<img ng-src="resources/{​{$item.name}}.png" /> {​{$item.name}}
CSS
/* 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: