Displaying and editing tabular data is an important part of most business applications. Regardless of whether your application deals with an employee list, a product catalog or a stock rates listing, you need some convenient means to visualize, transform (sort/group/filter) and edit tabular data. You may also need to display big lists of scrollable data without sacrificing the performance.
This is when data grid controls such as FlexGrid, our JavaScript DataGrid come into play. Luckily, FlexGrid is also available as a full-featured Angular DataGrid.
FlexGrid does a great job of displaying and editing tabular data out of the box. But there are cases when you need more than just a default data representation it provides. For example, you may need to render an image or a sparkline next to the data cell text. Or you want to add an interactive checkbox to the column header. Or you need some other type of cell content customization from the infinite number of possible options.
Defining UI Parts in an Angular Application
The most natural and convenient way to define UI parts in an Angular application is by using the templates syntax. And that would be a remarkable requirement to be able to use the same template syntax for describing the contents of grid cells. Cell templates allow you to do exactly that! Using cell templates, you can declaratively define cells content of an arbitrary complexity, which contains HTML elements and Angular components, that use property and event bindings.
FlexGrid is comprised of multiple cells of different types. Data cells, column headers, and footers, row headers are all the examples of the different types of cells. Cell templates allow you to declaratively define content for any cell type supported by FlexGrid, ten different cell types in total.
There is also a special type of cell template, the cell editor, which makes defining of a UI for data cells editing a breeze. Using it, you can accommodate advanced input controls like Wijmo InputNumber or InputDate, or your own custom component, to be a cell editor, without writing any single line of TypeScript code. Or you can create custom cell editors with a UI of arbitrary complexity.
Adding Angular Cell Templates
In this article, we'll refer to this live sample for the examples of cell template definitions. It demonstrates the use of cell templates with all types of the cells and allows a user to selectively enable or disable the application of cell templates to any specific type of the cell, by checking on or off the corresponding checkboxes.
So, let's expect that we have a Country column in our FlexGrid, and a set of country_name.png state flag images in the resources folder. And we want to draw a flag image next to the country name in the column's data cells.
The Angular template markup which defines cells content this way might look like:
<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>
</wj-flex-grid-column>
As you see, cell template is declared using the element with the wjFlexGridCellTemplate directive specified on it. The content of the element becomes the cells content. The cellType property specifies the type of cells this template should be applied to. Its 'Cell' value in the above example means regular data cells.
Because data cells are pertaining to a specific grid Column (the Country column in this example), we nest the cell template definition into the corresponding column definition (wj-flex-grid-column component).
Cell template needs cell-specific data to draw its content, which can be obtained via the cell local template variable (let-cell="cell"). It's an object with a few properties containing cell data. In this example we use the cell.item property that references a data item for the cell, and we retrieve the country property value from this item using the {{cell.item.country}} interpolation expressions. The other properties of the cell data object are cell.row (references cell's Row object) and cell.col (references cell's Column object).
Note that in our reference sample we allow a user to dynamically enable or disable cell templates of any specific type. The enabled state for the regular data cell templates is stored in the boolean customCell property of the sample's component. We add a *ngIf directive bound to this property to the ng-template element, to dynamically add or remove the cell template definition to/from the element tree. This way, we enable or disable the cell template applied to the specific column cells.
Some FlexGrid cell types are pertaining to a specific column, for example, regular data cells and column header/footer cells. While others like top-left and row header cells don't belong to any specific column. We'll call them column level and grid-level cells respectively. As we mentioned above, templates for column level cells should be declared inside their column component. In a similar way, grid-level cell templates should be defined as children of the wj-flex-grid component.
For example, to customize row headers to display a row index inside them, we can use the following cell template declaration nested in the wj-flex-grid element:
<wj-flex-grid [itemsSource]="data">
<ng-template wjFlexGridCellTemplate
[cellType]="'RowHeader'"
*ngIf="customRowHeader"
let-cell="cell">
\{{cell.row.index + 1}}
</ng-template>
........
</wj-flex-grid>
Note that we use the cell.row data context property here to retrieve the index of the row that this row header belongs to.
Cell Editors
FlexGrid provides a comprehensive data cell editing experience out of the box. By double-clicking on a cell or typing a text into a selected cell, you switch the cell into the edit mode, where you can type a new cell value, and then save it by moving focus out of the cell, or by pressing the Enter key. By default, FlexGrid editors are just input elements where you can enter a new value using the keyboard. But sometimes you may want to provide a user with a more sophisticated editing experience. For example, you may want to have a drop-down calendar as a date cell editor, or use a numeric input control with increment/decrement buttons for numeric cells. Or you may even need to create a complex editing UI comprising multiple input controls.
Cell templates allow you to create cell editors in the same convenient way as you use to create templates for other cell types.
For example, this template uses a Wijmo InputNumber control as an editor for the numeric Downloads column:
<wj-flex-grid-column header="Downloads" binding="downloads" [width]="170">
<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>
</wj-flex-grid-column>
The special 'CellEdit' cellType denotes a template used as the column's cell editor.
The cell data context object adds an additional cell.value property for this type of template, which stores a raw cell value. Changing this property value will force FlexGrid to store it as a new cell value when cell editing is finished. As a result, in most cases, it's just enough to establish a two-way binding between cell.value and the input control property that stores a control value entered by a user.
Like in our example, where we use wj-input-number component with the [(value)]="cell.value" two-way binding. Note that not a single line of TypeScript code was needed to create a fully functional cell editor, everything was done absolutely declaratively.
Conclusion
FlexGrid cell templates is a powerful mechanism for defining custom cell content. It utilizes the same usual Angular template syntax that you use to describe the rest of the UI of your application. With arbitrary HTML elements, custom components and directives inside the templates, which can use property and event bindings, you can declaratively create a complex look for the cells, without writing a single line of TypeScript code. The use of the cell templates makes you more productive in the implementation of complex grid UI, and makes the overall application code easier to maintain.
More details about Angular DataGrid cell templates can be found in the documentation.
The reference sample used in this article is a good start point to understand the use of cell templates for different cell types.
Additional Resources:
React Cell Templates for the FlexGrid | Vue Cell Templates for the FlexGrid