Custom Editors for FlexGrid
The FlexGrid , our JavaScript DataGrid, has always had advanced Excel-style editing built-in. By default, it provides:
- In-cell editing
- Quick editing
- List-based editing (via data maps)
- Checkbox editing (for Boolean cells)
- Validation support
But many customers wanted to enhance and customize the editing experience using custom controls as cell editors. To address that need, we added editing templates to our interop modules and created a CustomGridEditor sample for pure JS applications.
The CustomGridEditor sample turned out to be very popular, but using it was hard because it was just a sample, not easy to find, not well-maintained, and not correctly integrated with the grid. Also, it lacked IME support for quick editing, which made it awkward to use in countries like China, Japan, and Korea.
FlexGrid is also available as an Angular DataGrid, React DataGrid and Vue DataGrid.
What's New with Column Editors
In our 2020 v2 release, we addressed this by adding an editor property to the FlexGrid's Column class.
With the new editor property, you can:
- Use any Wijmo control as an editor for the column
- Fully customize the editor using their regular object model
- Use a single control as an editor for multiple columns
- Automatically display drop-down buttons when not in edit mode
The column editors integrate entirely with the grid, with support for CollectionView-based validation and full IME support.
The column editors are regular Wijmo controls, so they have robust and familiar object models, with nothing new to learn. And you have several powerful controls to choose from.
Try a live demo of Custom Editors in your framework of choice:
Typical Use Cases for Custom Editors
How to Use InputDate for Column Editors
My favorite use case for column editors is date input. By default, the grid allows users to edit dates as strings, parsed according to the column's format. This method works well and allows for quick and safe data entry.
But sometimes you really want to click a button and pick the date from a calendar. In those cases, you can use an InputDate control as a cell editor.
For example:
import { DataType } from '@grapecity/wijmo';
import { InputDate } from '@grapecity/wijmo.input';
import { FlexGrid } from '@grapecity/wijmo.grid';
// create the grid
let theGrid = new FlexGrid('#theGrid', {
itemsSource: getData()
});
// create an InputDate to use as a cell editor
let theInputDate = new InputDate('#theInputDate');
// assign the editor to all date columns
theGrid.columns.forEach(col => {
if (col.dataType == DataType.Date) {
col.editor = theInputDate;
}
});
The result is this:
Users can still type in the dates if they choose to, but now they can click the drop-down button to see a calendar where they can select the month and year, and then pick the date with a click.
You can customize the editor as you wish using CSS and the InputDate rich object model.
How to Use InputTime for Column Editors
InputTime can also be useful. It is like InputDate but allows users to edit the time part of date objects instead of the date.
InputTime provides a drop-down list with auto-completion, which makes it easier for users to select times.
For example:
import { InputTime } from '@grapecity/wijmo.input';
import { FlexGrid } from '@grapecity/wijmo.grid';
// create the grid
let theGrid = new FlexGrid('#theGrid', {
itemsSource: getData()
});
// create an InputTime to use as a cell editor
let theInputTime = new InputTime(document.createElement('div'), {
isEditable: true,
format: 't',
min: '7:00',
max: '22:00',
step: 30
});
// assign the editor to the 'time' column
let col = theGrid.getColumn('time');
col.format = 't'; // short time format
col.editor = theInputTime;
The result is this:
Notice how the editor shows a list that spans the range between the min and max values provided in intervals of 30 minutes. With the isEditable property set to true, users can type times, not on the list (such as "10:47").
How to Use InputDateTime
The InputDateTime control extends InputDate to allow editing in both time parts of date objects. It is a lot more convenient to use than typing, which is error-prone in cells that contain this much information.
For example:
import { InputDateTime } from '@grapecity/wijmo.input';
import { FlexGrid } from '@grapecity/wijmo.grid';
// create the grid
let theGrid = new FlexGrid('#theGrid', {
itemsSource: getData()
});
// create an InputDateTime to use as a cell editor
let theInputDateTime = new InputDateTime(document.createElement('div'), {
timeMin: '7:00',
timeMax: '22:00',
timeStep: 30
});
// assign the editor to the 'date' column
let col = theGrid.getColumn('date');
col.format = 'g'; // date and time
col.editor = theInputTime;
The result is this:
Notice how the editor has two drop-down buttons, one for selecting the date and one for time.
How to Use ComboBox in Columns without Data Maps
ComboBox controls are not much different from the default pickers used to edit data-mapped columns.
But they provide a richer object model and can be used in columns without data maps.
For example:
import { ComboBox } from '@grapecity/wijmo.input';
import { FlexGrid } from '@grapecity/wijmo.grid';
// create the grid
let theGrid = new FlexGrid('#theGrid', {
itemsSource: getData()
});
// create a ComboBox to use as a cell editor
let theComboBox = new ComboBox (document.createElement('div'), {
itemsSource: getCountries()
});
// assign the editor to the 'country' column
theGrid.getColumn('country') = theComboBox;
The result is this:
If the column had a data map, this is almost identical to what you would get with the built-in editor. But in this case, you have access to the control, and you can customize it using the object model and CSS. For example, you could use some CSS to create a multi-column drop-down:
How to Use AutoComplete with Lists
The AutoComplete control is like the ComboBox, but better suited for lists with lots of items, including support for async loading and full-text, customizable searching.
How to Use InputNumber to Edit Numeric Columns
The InputNumber control can be used to edit numeric columns. Compared to the built-in editor, it offers a couple of advantages:
- Users will edit formatted values.
- You can restrict the range of editable values by setting the min and max properties.
- You can use the step property to provide increment/decrement buttons.
For example:
import { InputNumber } from '@grapecity/wijmo.input';
import { FlexGrid } from '@grapecity/wijmo.grid';
// create the grid
let theGrid = new FlexGrid('#theGrid', {
itemsSource: getData()
});
// create an InputNumber to use as a cell editor
let theInputNumber = new InputNumber (document.createElement('div'), {
min: 0,
max: 1000,
format: 'n2'
});
// assign the editor to the 'amount' column
theGrid.getColumn('amout') = theInputNumber;
The result is this:
How to Use Miscellaneous Input Controls
The steps above illustrate how the editor property works with several Wijmo input controls. Many others can be used, including:
- InputColor: Input colors by picking them from a palette
- MultiSelect: Select multiple items from arrays
- InputMask: Edit utilizing a mask
- You Own Controls: You can create editors by extending Wijmo's Control class. Just make sure your control has a value or text property, and you are good to go!
Implementing Boolean Columns
In addition to the new editor property, you may have noticed that we changed the markup used to display Boolean values in grid columns.
Originally, we used a simple input element. In the last release, we wrapped that in a label element and added an empty span after the input:
<div class="wj-cell">
<label>
<input type="checkbox" class="wj-cell-check">
<span></span>
</label>
</div>
The new Boolean cells look and behave like the old ones, but they can be styled using CSS.
There are many blogs discussing techniques for styling checkboxes and radio buttons. These techniques rely on input elements having adjacent elements so you can use the ":before" and ":after" CSS selectors (which are not available for input elements).
For example, the CSS below can be used to turn the checkboxes in a column into "switch" elements:
.wj-cell.switch input[type=checkbox] { /* switch-style checkbox */
opacity: 0;
width: 100%;
}
.wj-cell.switch input[type=checkbox]+span {
pointer-events: none;
background: rgba(0, 0, 0, 0.4);
}
.wj-cell.switch input[type=checkbox]:checked+span {
background: #0085c7;
}
.wj-cell.switch input[type=checkbox]+span:before { /* switch track */
content: '';
display: block;
position: absolute;
left: 0; top: .45em; width: 2.5em; height: .75em;
border-radius: 1em;
background: rgba(0, 0, 0, .4);
opacity: .25;
}
.wj-cell.switch input[type=checkbox]:checked+span:before
background: inherit;
}
.wj-cell.switch input[type=checkbox]+span:after { /* switch thumb */
content: '';
position: absolute;
left: 0; top: 0.13em; width: 1.3em; height: 1.3em;
background: white;
border-radius: 1em;
}
.wj-cell.switch input[type=checkbox]:checked+span:after {
left: 1.25em;
background: inherit;
}
If you now set a Boolean column's cssClass property to "switch," you will get this:
The switches work like regular checkboxes (actually, they are regular checkboxes with some visuals displayed above them).
We are using switches only as an example of the customizations possible with the new markup. They are not "modern checkboxes" and should not be used indiscriminately.
Switches are appropriate in some situations. For more details, please check the web for articles such as Checkbox vs Toggle Switch.
Editor Property vs. Interop Cell Templates
Wijmo's interop modules provide support for popular JavaScript frameworks, including Angular, React, and Vue. They have always supported custom editors using templates.
The new cellTemplate and editor properties overlap with the templating features provided by the interop modules. You can use either; it is mostly a matter of preference.
For example, this is how you would use an InputNumber control as an editor using the Angular interop module's wjFlxGridCellTemplate directive:
<wj-flex-grid-column binding="downloads">
<ng-template wjFlexGridCellTemplate
[cellType]="'CellEdit'"
let-cell="cell">
<wj-input-number
[(value)]="cell.value"
[step]="1">
</wj-input-number>
</ng-template>
</wj-flex-grid-column>
And this is how you would do it using the new editor property:
<wj-input-number #inputNumber [step]="1">
</wj-input-number>
<wj-flex-grid-column binding="downloads" editor="inputNumber">
</wj-flex-grid-column>
The main advantages of using the interop templates are:
- You get better framework integration, with editors defined right in the markup.
- You can define templates for all cell types (editors, data, row and column headers, etc.).
The main advantages of the cellTemplate and editor properties are:
- They provide consistency across frameworks. You can use them with any framework or without any frameworks at all.
- You can easily re-use editors and apply them to multiple columns.
Moving Forward with Custom Editors
Support for custom editors has been on our to-do list for a long time. It is a popular request from our users and has been available through our interop modules for a long time. We are thrilled to offer this feature now. It makes the FlexGrid even more powerful and flexible.
Together with markup enhancements and the cellTemplate property, the editor property provides extensive and easy to use customization for all cell types.
We hope you enjoy it!