Framework:Javascript Data GridAngular Data GridReact Data GridVue Data Grid

JavaScript Data Grid: Cell Editors

Create your own cell editor by providing a cell editor component.

Simple Cell Editor

Below is a simple example of cell renderer class:

class DoublingEditor {
   init(params) {
       this.value = params.value;

       this.input = document.createElement('input');
       this.input.id = 'input';
       this.input.type = 'number';
       this.input.value = this.value;

       this.input.addEventListener('input', (event) => {
           this.value = event.target.value;
       });
   }

   /* Component Editor Lifecycle methods */
   // gets called once when grid ready to insert the element
   getGui() {
       return this.input;
   }

   // the final value to send to the grid, on completion of editing
   getValue() {
       // this simple editor doubles any value entered into the input
       return this.value * 2;
   }

   // Gets called once before editing starts, to give editor a chance to
   // cancel the editing before it even starts.
   isCancelBeforeStart() {
       return false;
   }

   // Gets called once when editing is finished (eg if Enter is pressed).
   // If you return true, then the result of the edit will be ignored.
   isCancelAfterEnd() {
       // our editor will reject any value greater than 1000
       return this.value > 1000;
   }

   // after this component has been created and inserted into the grid
   afterGuiAttached() {
       this.input.focus();
   }
}

Simple Cell Editor Example

The example below shows a few simple cell editors in action.

  • The Doubling Cell Editor will double a given input and reject values over a 1000
  • The Mood Cell Editor illustrates a slightly more complicated editor with values changed depending on the smiley chosen
  • The Numeric Cell Editor illustrates a slightly more complicated numeric editor to the Doubling editor above, with increased input validation and better initial carot behaviour

Cell Editor Component

The interface for the cell editor component is as follows:

interface ICellEditorComp {

   // gets called once after the editor is created
   init?(params: ICellEditorParams): void;

   // Gets called once after GUI is attached to DOM.
   // Useful if you want to focus or highlight a component
   // (this is not possible when the element is not attached)
   afterGuiAttached?(): void;

   // Mandatory - Return the DOM element of your editor, this is what the grid puts into the DOM
   getGui(): HTMLElement;

   // Mandatory - Return the final value - called by the grid once after editing is complete
   getValue(): any;

   // Gets called once by grid after editing is finished
   // if your editor needs to do any cleanup, do it here
   destroy?(): void;

   // Gets called once after initialised. If you return true, the editor will
   // appear in a popup, so is not constrained to the boundaries of the cell.
   // This is great if you want to, for example, provide you own custom dropdown list
   // for selection. Default is false (ie if you don't provide the method).
   isPopup?(): boolean;

   // Gets called once, only if isPopup() returns true. Return "over" if the
   // popup should cover the cell, or "under" if it should be positioned below
   // leaving the cell value visible. If this method is not present, the
   // default is "over"
   getPopupPosition?(): string;

   // Gets called once after initialised. If you return true, the editor will not be
   // used and the grid will continue editing. Use this to make a decision on editing
   // inside the init() function, eg maybe you want to only start editing if the user
   // hits a numeric key, but not a letter, if the editor is for numbers.
   isCancelBeforeStart?(): boolean;

   // Gets called once after editing is complete. If your return true, then the new
   // value will not be used. The editing will have no impact on the record. Use this
   // if you do not want a new value from your gui, i.e. you want to cancel the editing.
   isCancelAfterEnd?(): boolean;

   // If doing full line edit, then gets called when focus should be put into the editor
   focusIn?(): boolean;

   // If doing full line edit, then gets called when focus is leaving the editor
   focusOut?(): boolean;
}

The params object provided to the init method of the cell editor has the following interface:

ICellEditorParams

Properties available on the ICellEditorParams interface.

value
any
Current value of the cell
eventKey
string | null
Key value of key that started the edit, eg 'Enter' or 'Delete' - non-printable characters appear here
charPress
string | null
The string that started the edit, eg 'a' if letter 'a' was pressed, or 'A' if shift + letter 'a' only printable characters appear here
column
Grid column
colDef
Column definition
node
Row node for the cell
data
any
Row data
rowIndex
number
Editing row index
cellStartedEdit
boolean
If doing full row edit, this is true if the cell is the one that started the edit (eg it is the cell the use double clicked on, or pressed a key on etc).
onKeyDown
Function
callback to tell grid a key was pressed - useful to pass control key events (tab, arrows etc) back to grid - however you do
onKeyDown = (event: KeyboardEvent) => void;
stopEditing
Function
Callback to tell grid to stop editing the current cell. Call with input parameter true to prevent focus from moving to the next cell after editing stops in case the grid property enterMovesDownAfterEdit=true
stopEditing = (
    suppressNavigateAfterEdit?: boolean
) => void;
eGridCell
A reference to the DOM element representing the grid cell that your component will live inside. Useful if you want to add event listeners or classes at this level. This is the DOM element that gets browser focus when selecting cells.
parseValue
Function
Utility function to parse a value using the column's colDef.valueParser
parseValue = (value: any) => any;
formatValue
Function
Utility function to format a value using the column's colDef.valueFormatter
formatValue = (value: any) => any;
api
The grid api.
columnApi
The column api.
context
any
Application context as set on gridOptions.context.

Registering Cell Editors with Columns

See the section registering custom components for details on registering and using custom cell editors.

Complementing Cell Editor Params

As with cell renderers, cell editors can also be provided with additional parameters. Do this using cellEditorParams as in the following example which will pass 'Ireland' as the 'country' parameter:

colDef = {
   cellEditor: MyCellEditor,    
   cellEditorParams: {
       // make "country" value available to cell editor
       country: 'Ireland'
   },
   // ...other props
}

Configure Popup

Configure that a Custom Cell Editor is in a popup in one of the following ways:

  1. Implement the isPopup() method on the Custom Cell Editor and return true.
  2. Specify cellEditorPopup=true on the Column Definition.
 colDef = {
    cellEditorPopup: true,
    // ...other props
}

Configure Popup Position

By default Popup Editors appear over the editing Cell. It is also possible to have the Cell Editor appear below the Cell, so the user can see the Cell contents while editing.

Configure the Popup Editor to appear below the Cell in one of the following ways:

  1. Implement the getPopupPosition() method on the Custom Cell Editor and return under.
  2. Specify cellEditorPopupPosition='under' on the Column Definition.
 colDef = {
    cellEditorPopupPosition: 'under',
    // ...other props
}

Keyboard Navigation While Editing

If you provide a cell editor, you may wish to disable some of the grids keyboard navigation. For example, if you are providing a simple text editor, you may wish the grid to do nothing when you press the right and left arrows (the default is the grid will move to the next / previous cell) as you may want the right and left arrows to move the cursor inside your editor. In other cell editors, you may wish the grid to behave as normal.

Because different cell editors will have different requirements on what the grid does, it is up to the cell editor to decide which event it wants the grid to handle and which it does not.

You have two options to stop the grid from doing it's default action on certain key events:

  1. Stop propagation of the event to the grid in the cell editor.
  2. Tell the grid to do nothing via the colDef.suppressKeyEvent() callback.

Option 1 - Stop Propagation

If you don't want the grid to act on an event, call event.stopPropagation(). The advantage of this method is that your cell editor takes care of everything, good for creating reusable cell editors.

The follow code snippet is one you could include for a simple text editor, which would stop the grid from doing navigation.

const KEY_LEFT = 'ArrowLeft';
const KEY_UP = 'ArrowUp';
const KEY_RIGHT = 'ArrowRight';
const KEY_DOWN = 'ArrowDown';
const KEY_PAGE_UP = 'PageUp';
const KEY_PAGE_DOWN = 'PageDown';
const KEY_PAGE_HOME = 'Home';
const KEY_PAGE_END = 'End';

eInputDomElement.addEventListener('keydown', event => {
   const key = event.key;

   const isNavigationKey = keyCode === KEY_LEFT || 
       key === KEY_RIGHT || 
       key === KEY_UP || 
       key === KEY_DOWN || 
       key === KEY_PAGE_DOWN || 
       key === KEY_PAGE_UP || 
       key === KEY_PAGE_HOME || 
       key === KEY_PAGE_END;

   if (isNavigationKey) {
       // this stops the grid from receiving the event and executing keyboard navigation
       event.stopPropagation();
   }
})

Option 2 - Suppress Keyboard Event

If you implement colDef.suppressKeyboardEvent(), you can tell the grid which events you want process and which not. The advantage of this method of the previous method is it takes the responsibility out of the cell editor and into the column definition. So if you are using a reusable, or third party, cell editor, and the editor doesn't have this logic in it, you can add the logic via configuration.

suppressKeyboardEvent
Function
Allows the user to suppress certain keyboard events in the grid cell.
Default: false
suppressKeyboardEvent = (
    params: SuppressKeyboardEventParams
) => boolean;

interface SuppressKeyboardEventParams {
  // The keyboard event the grid received 
  event: KeyboardEvent;
  // Whether the cell is editing or not 
  editing: boolean;
  // Row node for the given row 
  node: RowNode;
  // Data associated with the node 
  data: any;
  // Column for this callback 
  column: Column;
  // ColDef provided for this column 
  colDef: ColDef;
  // The grid api. 
  api: GridApi;
  // The column api. 
  columnApi: ColumnApi;
  // Application context as set on `gridOptions.context`. 
  context: any;
}
const KEY_UP = 'ArrowUp';
const KEY_DOWN = 'ArrowDown';

colDef.suppressKeyboardEvent = params => {
   console.log('cell is editing: ' + params.editing);
   console.log('keyboard event:', params.event);

   // return true (to suppress) if editing and user hit up/down keys
   const key = params.event.key;
   const gridShouldDoNothing = params.editing && (key === KEY_UP || key === KEY_DOWN);
   return gridShouldDoNothing;
}

Cell Editing Example

The example below illustrates:

  • 'Gender' column uses a Component cell editor that allows choices via a 'richSelect' (AG Grid Enterprise only), with values supplied by complementing the editor parameters.
  • 'Age' column uses a Component cell editor that allows simple integer input only.
  • 'Mood' column uses a custom Component cell editor and renderer that allows choice of mood based on image selection.
  • 'Address' column uses a Component cell editor that allows input of multiline text via a 'largeText'. Tab and Esc (amongst others) will exit editing in this field, Shift+Enter will allow newlines.
  • 'Country' columns shows using 'richSelect' for a complex object - the cell renderer takes care of only rendering the country name.

Accessing Cell Editor Instances

After the grid has created an instance of a cell editor for a cell it is possible to access that instance. This is useful if you want to call a method that you provide on the cell editor that has nothing to do with the operation of the grid. Accessing cell editors is done using the grid API getCellEditorInstances(params).

getCellEditorInstances
Function
Returns the list of active cell editor instances. Optionally provide parameters to restrict to certain columns / row nodes.
getCellEditorInstances = (
    params: GetCellEditorInstancesParams = {}
) => ICellEditor[];

interface GetCellEditorInstancesParams {
  // Optional list of row nodes to restrict operation to 
  rowNodes?: RowNode[];
  // Optional list of columns to restrict operation to 
  columns?: (string | Column)[];
}

If you are doing normal editing, then only one cell is editable at any given time. For this reason if you call getCellEditorInstances() with no params, it will return back the editing cell's editor if a cell is editing, or an empty list if no cell is editing.

An example of calling getCellEditorInstances() is as follows:

const instances = gridOptions.api.getCellEditorInstances(params);
if (instances.length > 0) {
    const instance = instances[0];
}

The example below shows using getCellEditorInstances. The following can be noted:

  • All cells are editable.
  • First Name and Last Name use the default editor.
  • All other columns use the provided MySimpleCellEditor editor.
  • The example sets an interval to print information from the active cell editor. There are three results: 1) No editing 2) Editing with default cell renderer and 3) editing with the custom cell editor. All results are printed to the developer console.