DevExtreme React Grid - Custom Editors

Oliver's Blog
05 July 2017

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 template functions to editCellTemplate on the TableEditRow plugin and filterCellTemplate on the TableFilterRow.

<TableFilterRow filterCellTemplate={ this.selectFilterEditor } />
<TableEditRow editCellTemplate={ this.selectCellEditor } />

It is a bit unfortunate that the two template functions 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:

Click here to return to the blog series overview

Free DevExpress Products - Get Your Copy Today

The following free DevExpress product offers remain available. Should you have any questions about the free offers below, please submit a ticket via the DevExpress Support Center at your convenience. We'll be happy to follow-up.
No Comments

Please login or register to post comments.