React Cell Templates for the FlexGrid

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,y ou 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.

FlexGrid 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 and footers, 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 React 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.

Adding React Cell Templates

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 React JSX which defines cells content this way might look like:

<wjGrid.FlexGridColumn header="Country" binding="country" width="*">
    <wjGrid.FlexGridCellTemplate
        cellType="Cell"
        template=(context) => {
            return <React.Fragment>
               <img src={`resources/${context.item.country}.png`} />
               {context.item.country}
            </React.Fragment>
         } />
</wjGrid.FlexGridColumn>

As you see, the cell template is declared using the FlexGridCellTemplate component. 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.

The content of cells is defined using the template render prop, which is a function that returns JSX representing cell content. The context parameter of the function passes information about the rendering cell. It's an object with a few properties containing cell data. In this example we use the context.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} JSX expressions. The other properties of the cell data object are cell.row (references the cell's Row object) and cell.col (references the cell's Column object).

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 (FlexGridColumn component).

Note that in our reference sample we allow a user to dynamically enable or disable cell templates of any specific type. For clarity, we omitted the piece of code that makes it possible in the example above. Now let's investigate how it can be implemented.

The enabled state for the regular data cell templates is stored in the boolean customCell property of the main sample component. There are two options to disable the template - set its template property to a null value, or exclude the whole FlexGridCellTemplate component from rendering.

The first approach is probably more convenient, the code that implements it may look like:

<wjGrid.FlexGridColumn header="Country" binding="country" width="*">
    <wjGrid.FlexGridCellTemplate
        cellType="Cell"
        template={!this.state.customCell ? null : (context) => {
            return <React.Fragment>
               <img src={`resources/${context.item.country}.png`} />
               {context.item.country}
            </React.Fragment>
         }} />
</wjGrid.FlexGridColumn>

Some FlexGrid cell types are pertaining to a specific column, for example regular data cells and column header/footer cells. While the others like top-left and row header cells don't belong to any column. We'll call them column-evel and grid level cells respectively. As we mentioned above, templates for column-evel cells should be declared inside their column component. In the similar way, grid level cell templates should be defined as children of the FlexGrid 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 FlexGrid element:

<wjGrid.FlexGrid itemsSource={this.state.itemsSource}>
    <wjGrid.FlexGridCellTemplate
        cellType="RowHeader"
        template=(context) => context.row.index + 1 />
</wjGrid.FlexGrid>

Note that we use the context.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 cells 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 more sophisticated editing experience. For example, you may want to have a drop-down calendar as a date cells 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 allows 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:

<wjGrid.FlexGridColumn header="Downloads" binding="downloads">
    <wjGrid.FlexGridCellTemplate
        cellType="CellEdit"
        template=(context) => {
            return <wjInput.InputNumber
                className="cell-editor"
                step={1}
                value={context.value}
                valueChanged={(inpNum) =>
                    context.value = inpNum.value}>
            </wjInput.InputNumber>
         } />
</wjGrid.FlexGridColumn>

The special CellEdit cellType denotes a template used as the column's cell editor.

The cell data context object adds an additional context.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. We bind the InputNumber.value property to this context property to initialize the control with the original cell value. And we use control's valueChanged event to update context.value with the new control value entered by a user.

Conclusion

FlexGrid cell templates can be used as a powerful means to define custom cell content. It utilizes the same usual React JSX syntax that you use to describe the rest of UI of your application. With arbitrary HTML elements and custom components inside the templates, which can use property and event bindings, you can declaratively create complex look for the cells. 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 React 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.

Try Wijmo's JavaScript UI controls free for 30 days

Download the latest version of Wijmo

Download Now!