This post is part of a series about the DevExtreme React Grid. You can find the introduction and overview to the post series by following this link.
At this point of its development, the DevExtreme React Grid doesn’t have any built-in functionality to utilize data type specific editors. However, it is easily possible to embed your own editors for certain types, and there is no shortage of existing solutions for UI libraries like Bootstrap.
In the sample for this post (below), I am assigning handlers to the event editCellTemplate
on the TableEditRow
plugin and the event filterCellTemplate
on the TableFilterRow
.
<TableFilterRow filterCellTemplate={ this.selectFilterEditor } /><TableEditRow editCellTemplate={ this.selectCellEditor } />
It is a bit unfortunate that the two event handlers differ in their signatures, so that the processes of embedding an editor for data editing vs embedding it for filtering are slightly different as well. Our developers are considering this use case and I hope this will become easier in the future.
Here are the two functions selectCellEditor
and selectFilterEditor
:
selectCellEditor({ column, value, onValueChange }) { if (column.name === "year") return (<CellIntEditor value={value} onValueChange={onValueChange} />); else return undefined; } selectFilterEditor({ column, filter, setFilter }) { const setFilterNumber = number => setFilter(number ? { value: number } : null); if (column.name === "year") return (<FilterIntEditor value={filter ? filter.value : null} onValueChange={setFilterNumber} />); else return undefined; }
In both cases the main distinction is about the column that requires an editor at this point. In my sample, I’m using a special number editor and this can be activated for the year
column. In other cases I’m returning undefined
.
Note that undefined
has a special meaning here by indicating that the default editor for the column should be rendered. If you were to return null
instead of undefined
, you would get no editor at all (which is standard React behavior for null
values.)
selectCellEditor
receives the two parameters value
and onValueChange
, which allow the editor to hook into the editing logic of the Grid. The value
should be displayed (and provided for editing) by the editor, an onValueChange
will have to be called when the editor changes the value, to notify the Grid of the change.
For selectFilterEditor
, things are logically the same, but different in their implementation. The filter
parameter contains a structure as defined for FilteringState
, and the value that will be shown by the editor needs to extracted from that structure first. In a similar way, the correct structure needs to be created for the setFilter
call, which requires a bit of extra logic.
With these items in place, what remains is the implementation of the CellIntEditor
and FilterIntEditor
components, which are returned by the two functions. The two components are implemented as functional components and they use a common editor called NumericInput
, available here.
const IntEditor = ({ value, onValueChange }) => (<NumericInput className="form-control" value={value} onChange={valueAsNumber => onValueChange(valueAsNumber)} /> ); const CellIntEditor = ({ value, onValueChange }) => (<td><IntEditor value={value} onValueChange={onValueChange} /></td> ); const FilterIntEditor = ({ value, onValueChange }) => (<th><IntEditor value={value} onValueChange={onValueChange} /></th> );
Another slightly unfortunate difference between data editors and filter editors is visible in this implementation. The template is expected to wrap the actual editors in HTML cell elements, which is required with the aim of increasing flexibility. However, for a data editor the wrapping element should be <td>
, whereas the filter lives in the table head and requires <th>
instead. Like I said before, I hope we’ll be able to iron out some of those differences in order make it easier to embed general-purpose editors.
As a final note: I’m going to introduce a larger sample in one of the upcoming posts of this series, where I will embed a date editor in addition to a number editor, and cover Material UI in addition to Bootstrap. The mechanisms are the same as those explained in this post, but the upcoming demo provides some additional illustrations.
That’s all! Here is the sample with the embedded editors: