Grid Cell Editing

Cells Editing in Grid

Grid Cell Editing

The following code shows how to enable the cell editing in Grid. To enable the editing, the editing.enabled should be set to true and depending on the chosen editing.mode the editing would be single cell or full row. The default editing mode is "cell" and we will describe it in this topic. The code sample below shows how to enable cell editing.
const gridOptions = {
    dataSourceSettings: {
        dataFields: [
            { name: 'firstName', dataType: 'string' },
            { name: 'lastName', dataType: 'string' },
            { name: 'productName', map: 'product.name', dataType: 'string' },
            { name: 'payment', map: 'product.payment', dataType: 'string' },
            { name: 'quantity', map: 'product.quantity', dataType: 'number' },
            { name: 'price', map: 'product.price', dataType: 'number' },
            { name: 'total', map: 'product.total', dataType: 'number' }
        ]
    },
    editing: {
        enabled: true
    },
    selection: {
        enabled: true,
        allowCellSelection: true,
        mode: 'extended'
    },
    filtering: {
        enabled: true
    },
    behavior: {
        allowColumnReorder: true,
        allowColumnFreeze: true,
        columnResizeMode: 'growAndShrink'
    },
    sorting: {
        enabled: true
    },
    dataSource: [
        {
            firstName: 'Andrew',
            lastName: 'Burke',
            product: {
                name: 'Ice Coffee', price: 10, quantity: 3, total: 30, payment: 'Visa'
            }
        },
        {
            firstName: 'Petra',
            lastName: 'Williams',
            product: {
                name: 'Espresso', price: 7, quantity: 5, total: 35, payment: 'Visa'
            }
        },
        {
            firstName: 'Anthony',
            lastName: 'Baker',
            product: {
                name: 'Frappucino', price: 6, quantity: 4, total: 24, payment: 'Mastercard'
            }
        }
    ],
    columns: [
        {
            label: 'First Name', dataField: 'firstName', width: 150
        },
        { label: 'Last Name', dataField: 'lastName', width: 150 },
        { label: 'Product', dataField: 'productName', width: 150 },
        {
            label: 'Quantity', dataField: 'quantity', cellsAlign: 'right', width: 150
        },
        {
            label: 'Unit Price', dataField: 'price', cellsAlign: 'right', cellsFormat: 'c2', width: 150
        }
    ]
}
When editing is enabled, the 'F2', 'Backspace', 'Space'. The 'Delete' key clears the cell content without starting an editing process, while the 'Backspace' key clears the cell and starts the editing. You can configure whether the editing starts on single or double mouse click. For configuration of the edit action, use the editing.action property. The possible values are 'none', 'click' and 'doubleClick'. Pressing any alpha-numeric character starts the editing, too. When that happens, the default editor places the pressed character into the edit field and the editing starts after that character.
The beginEdit(rowId, dataField), endEdit() and cancelEdit() methods can be used to start, end and cancel editing.
grid.beginEdit(0, 'firstName');
The onCellUpdate for cell editing and onRowUpdate for row editing are callback functions which allow you to confirm or cancel the data updates depending on custom conditions. The following code will confirm all changes except the 'Quantity' column updates when cell values are over 20.
onCellUpdate(cells, oldValues, values, confirm) {
	if (cells[0].column.dataField === 'quantity') {
		if (values[0] <= 20) {
			setTimeout(() => {
				confirm(true);
			}, 500);
		}
		else {
			setTimeout(() => {
				confirm(false);
			}, 500);
		}
	}
	else {
		confirm(true);
	}
}
If we want to achieve the same result by used the onRowUpdate function, we can use this:
onRowUpdate(indexes, rows, oldDatas, datas, confirm) {
	if (datas[0]['quantity'] <= 20) {
		setTimeout(() => {
			confirm(true);
		}, 500);
	}
	else {
		confirm(false);
	}
}
The events which you can use for handling edits are: beginEdit, endEdit and cancelEdit. For batch editing, saveBatchEdit and clearBatchEdit.
If you need to get the edit cells, you can use the getEditCells method. In cell edit mode, the method returns an array with one cell. When editing.mode is equal to "row", the returned value is an array of cells.
const cells = grid.getEditCells();

for (let i = 0; i < cells.length; i++) {
	// grid cell.
	const cell = cells[i];
	// row id.
	const rowID = cell.row.id;
	// data field.
	const dataField = cell.column.dataField;
	// cell value.
	const value = cell.value;
};

Editors

  • Input Editor
    The default cell editor is Input. When editing is enabled, unless you set the editor property, the editor will be Input element.
    grid input editor
  • Textarea Input Editor
    To handle multiline text editing, you can use the Textarea editor. To do this, the editor property should be set to the 'textArea' string value.
    columns: [
    	{ label: 'First Name', dataField: 'firstName', editor: 'textArea' },
    	{ label: 'Last Name', dataField: 'lastName', editor: 'textArea' },
    	{ label: 'Product', dataField: 'productName', width: 150, editor: 'textArea'
    	},
    	{ label: 'Quantity', dataField: 'quantity', editor: 'numberInput'
    	},
    	{ label: 'Unit Price', dataField: 'price', editor: 'numberInput', cellsFormat: 'c2' }
    ]
    

    grid textarea editor
  • Auto-complete Input Editor
    The auto-complete editor is similar to the Input, but uses the column's data and auto-completes the typed text.
    columns: [
    	{
    		label: 'First Name', dataField: 'firstName', editor: 'input'
    	},
    	{ label: 'Last Name', dataField: 'lastName', editor: 'autoComplete' },
    	{ label: 'Product', dataField: 'productName', editor: 'dropDownList' },
    	{
    		label: 'Quantity', dataField: 'quantity', cellsAlign: 'right', editor: 'numberInput'
    	},
    	{
    		label: 'Unit Price', dataField: 'price', cellsAlign: 'right', cellsFormat: 'c2', editor: 'numberInput'
    	}
    ]
    	

    grid auto complete editor
  • Dropdownlist Editor
    The dropdownlist editor allows you to choose an item from a dropdown-list of items. All items in that list are unique items from the column's data source. In the following code sample, the 'Product' column is with dropdownlist editor.
    columns: [
    	{
    		label: 'First Name', dataField: 'firstName', editor: 'input'
    	},
    	{ label: 'Last Name', dataField: 'lastName', editor: 'autoComplete' },
    	{ label: 'Product', dataField: 'productName', editor: 'dropDownList' },
    	{
    		label: 'Quantity', dataField: 'quantity', cellsAlign: 'right', editor: 'numberInput'
    	},
    	{
    		label: 'Unit Price', dataField: 'price', cellsAlign: 'right', cellsFormat: 'c2', editor: 'numberInput'
    	}
    ]
    	

    You can customize the items, by setting the editor property to an object.
    columns: [
    	{
    		label: 'First Name', dataField: 'firstName', editor: 'input'
    	},
    	{ label: 'Last Name', dataField: 'lastName', editor: 'autoComplete' },
    	{
    		label: 'Product', dataField: 'productName', template: 'dropDownList', editor: {
    			template: 'dropDownList',
    			dataSource: ["Black Tea", "Green Tea",
    				"Caffe Espresso", "Doubleshot Espresso",
    				"Caffe Latte", "White Chocolate Mocha",
    				"Caramel Latte", "Caffe Americano",
    				"Cappuccino", "Espresso Truffle",
    				"Espresso con Panna", "Peppermint Mocha Twist"]
    		}
    	},
    	{
    		label: 'Quantity', dataField: 'quantity', cellsAlign: 'right', editor: 'numberInput'
    	},
    	{
    		label: 'Unit Price', dataField: 'price', cellsAlign: 'right', cellsFormat: 'c2', editor: {
    			template: 'numberInput'
    		}
    	}
    ]
    

    grid custom dropdownlist editor
  • Combobox Editor
    The combobox editor allows you to input text and also to select items from a list of items similarly to the dropdownlist editor.
    columns: [
    	{
    		label: 'First Name', dataField: 'firstName', editor: 'input'
    	},
    	{ label: 'Last Name', dataField: 'lastName', editor: 'autoComplete' },
    	{
    		label: 'Product', dataField: 'productName', template: 'dropDownList', editor: {
    			template: 'comboBox',
    			dataSource: ["Black Tea", "Green Tea",
    				"Caffe Espresso", "Doubleshot Espresso",
    				"Caffe Latte", "White Chocolate Mocha",
    				"Caramel Latte", "Caffe Americano",
    				"Cappuccino", "Espresso Truffle",
    				"Espresso con Panna", "Peppermint Mocha Twist"]
    		}
    	},
    	{
    		label: 'Quantity', dataField: 'quantity', cellsAlign: 'right', editor: 'numberInput'
    	},
    	{
    		label: 'Unit Price', dataField: 'price', cellsAlign: 'right', cellsFormat: 'c2', editor: {
    			template: 'numberInput'
    		}
    	}
    ]
    	

    grid custom combobox editor
  • Date input editor
    The date input is the default editor for date columns. The following sample code shows how to create a date input editor and restrict the user input by using the 'min' and 'max' properties.
    columns: [
    	{
    		label: 'First Name', dataField: 'firstName'
    	},
    	{ label: 'Last Name', dataField: 'lastName' },
    	{ label: 'Product', dataField: 'productName' },
    	{
    		label: 'Date', dataField: 'date', cellsFormat: 'd', editor: {
    			template: 'dateInput',
    			min: new Date(2022, 5, 1),
    			max: new Date(2022, 10, 1)
    		}
    	},
    	{
    		label: 'Quantity', dataField: 'quantity', editor: 'numberInput'
    	},
    	{ label: 'Unit Price', dataField: 'price', editor: 'numberInput', cellsFormat: 'c2' }
    ]
    	

    grid date input editor
  • Time input editor
    The time input cell editor is applied to date/time columns by setting the editor property to 'timeInput'.
    const gridOptions = {
        dataSourceSettings: {
            dataFields: [
                { name: 'firstName', dataType: 'string' },
                { name: 'lastName', dataType: 'string' },
                { name: 'productName', map: 'product.name', dataType: 'string' },
                { name: 'payment', map: 'product.payment', dataType: 'string' },
                { name: 'quantity', map: 'product.quantity', dataType: 'number' },
                { name: 'price', map: 'product.price', dataType: 'number' },
                { name: 'total', map: 'product.total', dataType: 'number' },
                { name: 'date', dataType: 'date' }
            ]
        },
        editing: {
            enabled: true
        },
        selection: {
            enabled: true,
            allowCellSelection: true,
            mode: 'extended'
        },
        filtering: {
            enabled: true
        },
        behavior: {
            allowColumnReorder: true,
            allowColumnFreeze: true,
            columnResizeMode: 'growAndShrink'
        },
        sorting: {
            enabled: true
        },
        dataSource: [
            {
                firstName: 'Andrew',
                lastName: 'Burke',
                product: {
                    name: 'Ice Coffee', price: 10, quantity: 3, total: 30, payment: 'Visa'
                },
                date: new Date(2023, 5, 5)
            },
            {
                firstName: 'Petra',
                lastName: 'Williams',
                product: {
                    name: 'Espresso', price: 7, quantity: 5, total: 35, payment: 'Visa'
                },
                date: new Date(2023, 5, 5)
            },
            {
                firstName: 'Anthony',
                lastName: 'Baker',
                product: {
                    name: 'Frappucino', price: 6, quantity: 4, total: 24, payment: 'Mastercard'
                },
                date: new Date(2023, 5, 5)
            }
        ],
        columns: [
            {
                label: 'First Name', dataField: 'firstName', editor: 'input'
            },
            { label: 'Last Name', dataField: 'lastName', editor: 'autoComplete' },
            { label: 'Product', dataField: 'productName', editor: 'dropDownList' },
            {
                label: 'Quantity', dataField: 'quantity', cellsAlign: 'right', editor: 'numberInput'
            },
            {
                label: 'Unit Price', dataField: 'price', cellsAlign: 'right', cellsFormat: 'c2', editor: 'numberInput'
            },
            {
                label: 'Date', dataField: 'date', cellsAlign: 'right', cellsFormat: 'T', editor: 'timeInput'
            }
        ]
    }
    	

    grid time input editor
  • Datetime picker editor
    The date/time picker editor allows you to edit date/time values even when you need DateTime precision up to a yoctosecond (10⁻²⁴ second).
    columns: [
    	{
    		label: 'First Name', dataField: 'firstName', editor: 'input'
    	},
    	{ label: 'Last Name', dataField: 'lastName', editor: 'autoComplete' },
    	{ label: 'Product', dataField: 'productName', editor: 'dropDownList' },
    	{
    		label: 'Quantity', dataField: 'quantity', cellsAlign: 'right', editor: 'numberInput'
    	},
    	{
    		label: 'Unit Price', dataField: 'price', cellsAlign: 'right', cellsFormat: 'c2', editor: 'numberInput'
    	},
    	{
    		label: 'Date', dataField: 'date', cellsAlign: 'right', cellsFormat: 'd', editor: 'dateTimePicker'
    	}
    ]
    	

    grid datetimepicker editor
    If you need to customize the DateTimePicker's settings, you can set the 'editor' to an object like this:
    columns: [
    	{
    		label: 'First Name', dataField: 'firstName', editor: 'input'
    	},
    	{ label: 'Last Name', dataField: 'lastName', editor: 'autoComplete' },
    	{ label: 'Product', dataField: 'productName', editor: 'dropDownList' },
    	{
    		label: 'Quantity', dataField: 'quantity', cellsAlign: 'right', editor: 'numberInput'
    	},
    	{
    		label: 'Unit Price', dataField: 'price', cellsAlign: 'right', cellsFormat: 'c2', editor: {
    			template: 'numberInput',
    			min: 5,
    			max: 15
    		}
    	},
    	{
    		label: 'Date', dataField: 'date', cellsAlign: 'right', cellsFormat: 'd', editor: {
    			template: 'dateTimePicker',
    			importantDates: [
    				new Date(2022, 9, 20),
    				new Date(2022, 9, 9)
    			]
    		}
    	}
    ]
    

    grid custom datetimepicker editor
    The importantDates is a property from the DateTimePicker's API.
  • Number input editor
    The number input cell editor is built with the purpose to edit numbers in different formats. It restricts the user-input to numbers.
    columns: [
    	{
    		label: 'First Name', dataField: 'firstName', editor: 'input'
    	},
    	{ label: 'Last Name', dataField: 'lastName', editor: 'autoComplete' },
    	{ label: 'Product', dataField: 'productName', editor: 'dropDownList' },
    	{
    		label: 'Quantity', dataField: 'quantity', cellsAlign: 'right', editor: 'numberInput'
    	},
    	{
    		label: 'Unit Price', dataField: 'price', cellsAlign: 'right', cellsFormat: 'c2', editor: 'numberInput'
    	}
    ]
    	

    grid numeric editor
    The numeric editor can be used for currency, percentage and other types of numeric input.
    grid currency input editor
    You can restrict the input by customizing the editor. For example, the input value in the following code sample is restricted to minimum 5 and maximum 15.
    {
    	label: 'Unit Price', dataField: 'price', cellsAlign: 'right', cellsFormat: 'c2', editor: {
    		template: 'numberInput',
    		min: 5,
    		max: 15
    	}
    }
    	
  • Password editor
    To setup a password editor, you need to set the editor property to 'password'.
    {
    	label: 'First Name', dataField: 'firstName', editor: 'password'
    }
    	

    grid password editor
  • Image editor
    To setup an image editor, you need to set the editor property to 'image'.
    columns: [
    	{
    		label: 'First Name', dataField: 'firstName', editor: 'autoComplete'
    	},
    	{
    		label: 'Image', allowEdit: true, dataField: 'image', template: 'image', editor: {
    			template: 'image'
    		}
    	},
    	{ label: 'Available', dataField: 'available', template: 'checkBox', editor: 'checkBox' },
    	{ label: 'Quantity', dataField: 'quantity', editor: 'numberInput' },
    	{ label: 'Unit Price', dataField: 'price', editor: 'numberInput', cellsFormat: 'c2' }
    ]
    	

    grid image editor

    grid image dialog editor
  • Phone input editor
    The phone editor is used for editing phone numbers. It validates the entered phone number taking into account the country code.
    columns: [
    	{
    		label: 'First Name', dataField: 'firstName'
    	},
    	{ label: 'Last Name', dataField: 'lastName', editor: 'autoComplete' },
    	{ label: 'Product', dataField: 'productName', editor: 'dropDownList' },
    	{
    		label: 'Quantity', dataField: 'quantity', cellsAlign: 'right', editor: 'slider',
    	},
    	{
    		label: 'Unit Price', dataField: 'price', cellsAlign: 'right', cellsFormat: 'c2', editor: 'numberInput'
    	},
    	{
    		label: 'Phone Number', width: 300, dataField: 'phone', editor: 'phone'
    	}
    ]
    	

    grid phone input editor
  • Color input editor
    The color editor is used for colors. It can be used in combination with the 'color' template.
    columns: [
    	{
    		label: 'First Name', dataField: 'firstName'
    	},
    	{ label: 'Last Name', dataField: 'lastName', editor: 'autoComplete' },
    	{ label: 'Product', dataField: 'productName', editor: 'dropDownList' },
    	{
    		label: 'Quantity', dataField: 'quantity', cellsAlign: 'right', editor: 'slider',
    	},
    	{
    		label: 'Unit Price', dataField: 'price', cellsAlign: 'right', cellsFormat: 'c2', editor: 'numberInput'
    	},
    	{
    		label: 'Color input', width: 300, dataField: 'color', template: 'color', editor: 'colorInput'
    	}
    ]
    	

    grid color input editor
  • Mask Input editor
    The mask editor is used to edit alphanumeric values and to restrict the user input to a given mask.
    columns: [
    	{ label: 'Name', dataField: 'name', freeze: true, allowResize: true },
    	{
    		label: 'Project lead', width: 150, dataField: 'projectLead', allowResize: true
    	},
    	{
    		label: 'Phone', width: 200, dataField: 'phone', formatFunction(settings) {
    			const formatPhoneNumber = (value) => {
    				const formattedValue = ('' + value).replace(/\D/g, '');
    				const match = formattedValue.match(/^(1|)?(\d{3})(\d{3})(\d{4})$/);
    				if (match) {
    					let intlCode = (match[1] ? '+1 ' : '');
    					return [intlCode, '(', match[2], ') ', match[3], '-', match[4]].join('');
    				}
    				return null;
    			};
    			settings.value = formatPhoneNumber(settings.value);
    		}, editor: {
    			template: 'maskedTextBox',
    			mask: '(###) ### - ####'
    		}, allowResize: true
    	},
    	{
    		label: 'Project images', width: 200, dataField: 'projectImages', allowResize: true,
    		template: function (formatObject) {
    			formatObject.template = `<img style="width: 75px;" src="../../images/${formatObject.value}.jpg">`;
    		}
    	},
    	{
    		label: 'Category', width: 200, dataField: 'category', allowResize: true,
    		template: function (formatObject) {
    			let color;
    			if (formatObject.value === 'Brand indentity') {
    				color = '#007ACC';
    			}
    			else if (formatObject.value === 'Industrial design') {
    				color = '#CBC43F';
    			}
    			else {
    				color = '#9641A4';
    			}
    			formatObject.template = `<span style="margin-left: 7px; padding: 4px 18px; border-radius: 10px 5px; color: #fff; background: ${color}";>${formatObject.value}</span>`;
    		}
    	},
    	{ label: 'Done', width: 80, dataField: 'completed', template: 'checkBox', align: 'center', allowResize: true },
    	{
    		label: 'Client', width: 200, dataField: 'client', allowResize: true,
    		template: function (formatObject) {
    			formatObject.template = `<span style="margin-right: 7px; margin-left: 10px; padding: 4px 18px; border-radius: 10px 5px; background: #E9EEF9";>${formatObject.value}</span>`;
    		}
    	},
    	{
    		label: 'Project team', width: 300, dataField: 'projectTeam', allowResize: true
    	},
    	{ label: 'Kickoff date', editor: 'dateInput', width: 200, dataField: 'kickoffDate', cellsFormat: 'd', allowResize: true },
    	{ label: 'Due date', editor: 'dateInput', width: 200, dataField: 'dueDate', cellsFormat: 'd', allowResize: true }
    ]
    	

    grid masked input editor
  • Multi combo cell editor
    This editor is similar to the combobox, but it allows you to select multiple items. You can also customize the items look. This type of editor is usually combined with the 'tags' template.
    columns: [
    	{
    		label: 'First Name', dataField: 'firstName', template: 'dropDownList', editor: 'dropDownList'
    	},
    	{
    		label: 'Last Name', dataField: 'lastName', template: 'dropDownList', editor: 'dropDownList'
    	},
    	{
    		label: 'Product', allowEdit: true, width: 150, dataField: 'productName', template: 'tags', editor: {
    			template: 'multiComboInput'
    		}
    	},
    	{ label: 'Quantity', dataField: 'quantity', editor: 'numberInput' },
    	{ label: 'Unit Price', dataField: 'price', editor: 'numberInput', cellsFormat: 'c2' },
    	{
    		label: 'Supplier', width: 150, dataField: 'custom', template: 'tags',
    		editor: {
    			template: 'multiComboInput',
    			readonly: true,
    			dropDownButtonPosition: 'right',
    			autoOpen: true,
    			pills: true,
    			colorItems: true,
    			singleSelect: true,
    			dataSource: [
    				{ value: 0, color: '#8E24AA', label: 'Andrew', image: '../../images/people/andrew.png' },
    				{ value: 1, color: '#41B883', label: 'Anne', image: '../../images/people/anne.png' },
    				{ value: 2, color: '#53B9E6', label: 'Janet', image: '../../images/people/janet.png' },
    				{ value: 3, color: '#FFCD42', label: 'John', image: '../../images/people/john.png' },
    				{ value: 4, color: '#DD5347', label: 'Laura', image: '../../images/people/laura.png' }
    			]
    		}
    	}
    ]
    	

    grid combo input editor

    grid multi combo editor
  • Checkbox Boolean editor
    The checkbox editor is used for updating boolean values.
    columns: [
    	{
    		label: 'First Name', dataField: 'firstName'
    	},
    	{ label: 'Last Name', dataField: 'lastName' },
    	{ label: 'Product', dataField: 'productName' },
    	{ label: 'Available', dataField: 'available', template: 'checkBox', editor: 'checkBox' },
    	{ label: 'Quantity', dataField: 'quantity', editor: 'numberInput' },
    	{ label: 'Unit Price', dataField: 'price', editor: 'numberInput', cellsFormat: 'c2' }
    ]
    	

    grid checkbox input editor
  • Custom cell editor
    Custom cell editors could be used by setting the editor property. The following example shows how to setup a custom editor from HTMLTemplateElement and how to setup custom editor from HTML Input tags.
    columns: [
    	{
    		label: 'Mood', dataField: '', editor: {
    			template: '#moodEditorTemplate',
    			onInit(index, dataField, editor) {
    				editor.addEventListener('click', function (event) {
    					editor.firstElementChild.value = event.target.innerHTML;
    				});
    			}
    		}, width: 70, align: 'left', template: '#moodTemplate',
    	},
    	{
    		label: 'First Name', dataField: 'firstName', editor: '<input/>'
    	},
    	{
    		label: 'Last Name', dataField: 'lastName', editor: '<input/>'
    	},
    	{ label: 'Product', width: 200, dataField: 'productName', editor: '#template' },
    	{ label: 'Order Date', width: 200, dataField: 'date', editor: '<input type="date"/>'
    	},
    	{ label: 'Quantity', dataField: 'quantity', editor: '<input type="range"/>' },
    	{ label: 'Unit Price', dataField: 'price', editor: '<input type="number"/>', cellsFormat: 'c2' }
    ]
    	

    grid custom editor
    The 'onInit', 'onRender', 'setValue' and 'getValue' methods can be used when setting up a custom editor. 'onInit' is called once when the editor is created. It is used for initialization purposes. 'onRender' is called every time the editor is opened. 'setValue' is used for setting a value to the editor. 'getValue' should return the value which will be saved in the Grid after the editing.
    Let's look at the sample below which creates a Cascade editing with custom editors.
    columns: [
    	{
    		label: 'Country', dataField: 'Country', editor: {
    			template: '<smart-drop-down-list></smart-drop-down-list>',
    			onInit(row, column, editor) {
    				const dropDownList = editor.firstElementChild;
    				dropDownList.dataSource = ['Belgium', 'France', 'USA', 'Lebanon'];
    				dropDownList.dropDownAppendTo = 'body';
    				dropDownList.selectedValues = [grid.rows[row].cells[0].value];
    				dropDownList.addEventListener('change', function () {
    					change = true;
    				});
    			},
    			onRender(row, column, editor) {
    				editor.firstElementChild.selectedValues = [grid.rows[row].cells[0].value];
    			},
    			getValue() {
    				return this.firstElementChild.selectedValues[0];
    			}
    		}
    	},
    	{
    		label: 'City', dataField: 'City', editor: {
    			template: '<smart-drop-down-list></smart-drop-down-list>',
    			onInit(row, column, editor) {
    				const dropDownList = editor.firstElementChild;
    				dropDownList.dropDownAppendTo = 'body';
    				dropDownList.placeholder = 'Select a city...';
    			},
    			onRender(row, column, editor) {
    				const countryValue = grid.rows[row].cells[0].value, citiesSource = cities[countryValue], dropDownList = editor.firstElementChild;
    				dropDownList.dataSource = citiesSource;
    				dropDownList.selectedValues = [grid.rows[row].cells[1].value];
    			},
    			getValue() {
    				return this.firstElementChild.selectedValues[0] || 'Select a city...';
    			}
    		}
    	}
    ]
    

    grid cascade editor

Editing Validation

You can restrict the user input by defining validation rules. The validationRules property determines the validation rules of the column values. The available set of rules are: 'min', 'max', 'minLength', 'maxLength', 'minDate', 'maxDate', 'null', 'email', 'required', 'requiredTrue' and 'pattern'. A cell editor is active until a valid value is entered by the user. In the sample code below, 'First Name', 'Last Name' and 'Product Name' are with 'required' and 'minLength' validation rules. The 'Quantity' and 'Unit Price' columns are with 'min' and 'max' set to '1' and '20'. validation rules.
columns: [
	{
		label: 'First Name', dataField: 'firstName', validationRules: [{ type: 'required' }, { type: 'minLength', value: 5 }]
	},
	{ label: 'Last Name', dataField: 'lastName', validationRules: [{ type: 'required' }, { type: 'minLength', value: 5 }] },
	{ label: 'Product', dataField: 'productName', validationRules: [{ type: 'required' }, { type: 'minLength', value: 5 }] },
	{ label: 'Available', dataField: 'available', template: 'checkBox', editor: 'checkBox', validationRules: [{ type: 'requiredTrue' }] },
	{ label: 'Quantity', dataField: 'quantity', editor: 'numberInput', validationRules: [{ type: 'max', value: 20 }, { type: 'min', value: 1 }] },
	{ label: 'Unit Price', dataField: 'price', editor: 'numberInput', cellsFormat: 'c2', validationRules: [{ type: 'max', value: 20 }, { type: 'min', value: 1 }] }
]

grid validation editor

Undo/Redo

Undo/Redo is a common feature built-in the Grid. The following keyboard shortcuts are available when undo / redo is enabled:

Ctrl+Z: will undo the last cell edit(s).
Ctrl+Y: will redo the last undo.

Programatically, you can use the 'undo' and 'redo' methods.