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 an easy way 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 UI controls such as FlexGrid come into play.
Wijmo's Vue DataGrid does a great job in 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.
The most natural and convenient way to define UI parts in an Vue application is by using the templates syntax. And that would be a righteous requirement to be able to use the same template syntax for describing the contents of grid cells. Cell templates allows you to do exactly that! Using cell templates, you can declaratively define cells content of an arbitrary complexity, which contains HTML elements and Vue components, that use property and event bindings.
FlexGrid is comprised of multiple cells of different types. Data cells, column headers, footers, and row headers are all the examples of the different types of cells. Cell templates allows you to declaratively define a 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 JavaScript code. Or you can create custom cell editors with a UI of arbitrary complexity.
Adding Vue 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 Vue template markup which defines cells content this way might look like:
<wj-flex-grid-column header="Country" binding="country" width="*">
<wj-flex-grid-cell-template cellType="Cell" v-if="customCell" v-slot="cell">
<img :src="'resources/' + cell.item.country + '.png'" />
\{{cell.item.country}}
</wj-flex-grid-cell-template>
</wj-flex-grid-column>
As you see, the cell template is declared using the wj-flex-grid-cell-template component. The content of the wj-flex-grid-cell-template element becomes the content of the cell. 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).
A cell template needs cell-specific data to draw its content for every certain cell. Because of this, cell templates are implemented using the Vue scoped slot mechanism. The most simple and concise way to reference the cell scope properties is by using the new v-slot directive introduced in Vue 2.6.0. It gives a name to the data object containing slot specific properties, which can be used to reference these properties in the template markup. In the example above we call it cell (using the v-slot="cell" definition), and use its item property which references a data item for the cell. We retrieve the country property value from this item using the cell.item.country expression.
The other properties of the cell scope data object are row (references cell's Row object) and col (references cell's Column object).
Note that we can specify v-slot directive right on the wj-flex-grid-cell-template element. If you use Vue version lower than 2.6.0 where v-slot directive is absent, you can use its predecessor, the slot-scope directive, to reference the cell data context. In this case you have to wrap the template content with an additional <template>
element, where you specify slot-scope.
The example above reworked to use slot-scope might look like this:
<wj-flex-grid-column header="Country" binding="country" width="*">
<wj-flex-grid-cell-template cellType="Cell" v-if="customCell">
<template slot-scope="cell">
<img :src="'resources/' + cell.item.country + '.png'" />
\{{cell.item.country}}
</template>
</wj-flex-grid-cell-template>
</wj-flex-grid-column>
Notice how we added a <template>
element with the slot-scope="cell" directive on it.
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 v-if directive bound to this property to the wj-flex-grid-cell-template component, 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-evel and grid-level cells respectively. As we mentioned above, templates for column level cells should be declared inside their column components. 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="itemsSource">
<wj-flex-grid-cell-template cellType="RowHeader" v-if="customRowHeader" v-slot="cell">
\{{cell.row.index + 1}}
</wj-flex-grid-cell-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
Wijmo's Vue DataGrid 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">
<wj-flex-grid-cell-template cellType="CellEdit" v-if="customCellEdit" v-slot="cell">
<wj-input-number class="cell-editor"
v-model="cell.value"
:step="1"></wj-input-number>
</wj-flex-grid-cell-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 value property for this type of a 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 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 v-model="cell.value" two-way binding. You can also use an alternative two-way binding syntax, which utilizes the sync modifier. With it, the two-way binding definition would look like :value.sync="cell.value".
Learn more about Vue two-way bindings support in Wijmo.
Note that not a single line of JavaScript code was needed to create a fully functional cell editor, everything was done absolutely declaratively.
Vue Cell Templates for the FlexGrid Conclusion
FlexGrid cell templates can be used as a powerful means to define custom cell content. It utilizes the same usual Vue template syntax that you use to describe the rest of 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 JavaScript 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 Vue grid 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:
Angular Cell Templates for the FlexGrid | React Cell Templates for the FlexGrid