Although the FlexGrid control provides efficient, Excel-style editing by default, you may want to customize the grid's editing behavior. If you don't like the Excel-style editing and prefer to add editing buttons to the rows of your FlexGrid, you can accomplish that using the formatItem event and a little bit of code.
In this blog, we will outline how to perform inline editing with the FlexGrid control. We will create buttons that users can use to edit and delete rows inside the FlexGrid and insert input elements in the grid when the user begins editing the data.
Wijmo offers the fastest, most flexible JavaScript DataGrid with features including sorting, grouping, searching, Excel-like filtering, DataMaps, custom CellTemplates, sparklines, rich editing, Excel/PDF export, validation, DetailsRows, and more.
How to Import the Required Modules for FlexGrid
Before we can create our FlexGrid control, we’ll need to import the required Wijmo files into our JavaScript file:
import ‘@grapecity/wijmo.styles/wijmo.css’;
import * as wjCore from ‘@grapecity/wijmo’;
import * as wjGrid from ‘@grapecity/wijmo.grid’;
The above code will import Wijmo's main JavaScript module and the FlexGrid module; it also includes Wijmo's CSS file so that our control is styled correctly.
Creating the FlexGrid Control
First, we’ll need to create our FlexGrid control. We’ll be tying two events to our FlexGrid control as well: the formatItem event and the click event.
var theGrid = new wjGrid.FlexGrid(‘#theGrid’, {
isReadOnly: true,
selectionMode: ‘None’,
headersVisibility: ‘Column’,
itemsSource: data,
columns: [...],
});
theGrid.formatItem.addHandler(function(s,e){...});
theGrid.addEventListener(theGrid.hostElement, ‘click’, function(e)
{...});
We'll come back to these events later in the blog. Before that, we'll need to create our buttons that these events will use.
Adding Inline Editing Buttons
Next, we’ll need to create the button templates that our grid will use for inline editing. Both sets of buttons will be set to “display:none”, because these are just templates that we will be using in JavaScript, so we don’t want them to show up on-screen before then:
<!-- template for buttons on items in view mode -->
<div id="tplBtnViewMode" style="display:none">
<button id="btnEdit" class="btn btn-default btn-sm">
<span class="glyphicon glyphicon-pencil"></span> Edit
</button>
<button id="btnDelete" class="btn btn-default btn-sm">
<span class="glyphicon glyphicon-remove"></span> Delete
</button>
</div>
<!-- template for buttons on items in edit mode -->
<div id="tplBtnEditMode" style="display:none">
<button id="btnOK" class="btn btn-primary btn-sm">
<span class="glyphicon glyphicon-ok"></span> OK
</button>
<button id="btnCancel" class="btn btn-warning btn-sm">
<span class="glyphicon glyphicon-ban-circle"></span> Cancel
</button>
</div>
Implementing Inline Editing
Now that our FlexGrid has been created and we have our button templates, we can add code to the events that we have tied to the grid to implement inline editing. The formatItem event will handle what is being displayed in the FlexGrid, while the ‘click’ event listener will handle the buttons’ click events:
// custom formatter to paint buttons and editors
theGrid.formatItem.addHandler(function (s, e) {
if (e.panel == s.cells) {
var col = s.columns[e.col], item = s.rows[e.row].dataItem;
if (item == currentEditItem) {
// create editors and buttons for the item being edited
switch (col.binding) {
case 'buttons':
e.cell.innerHTML = document.getElementById('tplBtnEditMode').innerHTML;
e.cell['dataItem'] = item;
break;
case 'country':
case 'sales':
case 'expenses':
e.cell.innerHTML = '<input class="form-control" ' +
'id="' + col.binding + '" ' +
'value="' + s.getCellData(e.row, e.col, true) + '"/>';
break;
}
}
else {
// create buttons for items not being edited
switch (col.binding) {
case 'buttons':
e.cell.innerHTML = document.getElementById('tplBtnViewMode').innerHTML;
e.cell['dataItem'] = item;
break;
}
}
}
});
// handle button clicks
theGrid.addEventListener(theGrid.hostElement, 'click', function (e) {
let targetBtn;
if (e.target instanceof HTMLButtonElement) {
targetBtn = e.target;
}
else if (e.target instanceof HTMLSpanElement && e.target.classList.contains('glyphicon')) {
targetBtn = e.target.parentElement;
}
if (targetBtn) {
// get button's data item
var item = wjCore.closest(targetBtn, '.wj-cell')['dataItem'];
// handle buttons
switch (targetBtn.id) {
// start editing this item
case 'btnEdit':
editItem(item);
break;
// remove this item from the collection
case 'btnDelete':
theGrid.collectionView.remove(item);
break;
// commit edits
case 'btnOK':
commitEdit();
break;
// cancel edits
case 'btnCancel':
cancelEdit();
break;
}
}
});
You’ll notice a couple of custom functions that we call inside of our click event: editItem(), commitEdit(), and cancelEdit(). These are called based on which button the user clicks, and will update the FlexGrid accordingly based on the user’s selection.
var currentEditItem = null;
function editItem(item) {
cancelEdit();
currentEditItem = item;
theGrid.invalidate();
}
function commitEdit() {
if (currentEditItem) {
theGrid.columns.forEach(function (col) {
var input = theGrid.hostElement.querySelector('#' + col.binding);
if (input) {
var value = wjCore.changeType(input.value, col.dataType, col.format);
if (wjCore.getType(value) == col.dataType) {
currentEditItem[col.binding] = value;
}
}
});
}
currentEditItem = null;
theGrid.invalidate();
}
function cancelEdit() {
if (currentEditItem) {
currentEditItem = null;
theGrid.invalidate();
}
}
There's one final thing that we need to do. The buttons and input controls that we place inside the FlexGrid control are slightly taller than the cells they will be placed in. This means that we'll need to increase the height of our rows:
theGrid.rows.defaultSize = 40;
And that’s it! Your FlexGrid now supports inline editing through the use of buttons placed in the grid.
You can check out this sample live here.