Expand All

  Getting Started

  Interfacing

  Features

  Row Models

  Themes

  Components

  Examples

  Third Party

Misc

Github stars make projects look great. Please help, donate a star, it's free.
Read about ag-Grid's Partnership with webpack.
Get informed on releases and other ag-Grid news only - never spam.
Follow on Twitter

Cell Editors

Create your own cellEditor by providing a cellEditor component.

The interface for the cellEditor 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;

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

    // Should return the final value to the grid, the result of the editing
    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
    isPopup?(): boolean;

    // Gets called once before editing starts, to give editor a chance to
    // cancel the editing before it even starts.
    isCancelBeforeStart?(): boolean;

    // 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?(): boolean;

    // If doing full row edit, then gets called when tabbing into the cell.
    focusIn?(): boolean;

    // If doing full row edit, then gets called when tabbing out of the cell.
    focusOut?(): boolean;
}

Below is a simple example of cellEditor class:

// function to act as a class
function MyCellEditor () {}

// gets called once before the renderer is used
MyCellEditor.prototype.init = function(params) {
    // create the cell
    this.eInput = document.createElement('input');
    this.eInput.value = params.value;
};

// gets called once when grid ready to insert the element
MyCellEditor.prototype.getGui = function() {
    return this.eInput;
};

// focus and select can be done after the gui is attached
MyCellEditor.prototype.afterGuiAttached = function() {
    this.eInput.focus();
    this.eInput.select();
};

// returns the new value after editing
MyCellEditor.prototype.getValue = function() {
    return this.eInput.value;
};

// any cleanup we need to be done here
MyCellEditor.prototype.destroy = function() {
    // but this example is simple, no cleanup, we could
    // even leave this method out as it's optional
};

// if true, then this editor will appear in a popup 
MyCellEditor.prototype.isPopup = function() {
     and we could leave this method out also, false is the default
    return false;
};

cellEditor Params

The cellEditor component takes parameters in its init() method and contain the following:

Value Description
value The initial data value to be edited.
keyPress If editing was started by a function key press, contains the key code.
charPress If editing was started by a printable character, contains the string of the printable character.
column The column the cell belongs to.
node The row node the row is rendering.
api Grid API
columnApi Column API
context Grid context
$scope If compiling to Angular, is the row's child scope, otherwise null.
onKeyDown Callback to tell grid a key was pressed - useful to pass control key events (tab, arrows etc) back to grid - however you do not need to call this as the grid is already listening for the events as they propagate. This is only required if you are preventing event propagation.
stopEditing Callback to tell grid to stop editing the current cell.
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.
cellStartedEdit 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).

Complementing cellEditor Params

Again like cellRenderers, cellEditors can also be provided with additional parameters. Do this using cellEditorParams like in the following example which will pass 'Ireland' as the 'country' parameter:

// define cellRenderer to be reused
var myCellEditor = .....

// use with a color
colDef.cellEditor = ... // provide cellEditor as before
colDef.cellEditorParams = {
    country: 'Ireland'
}

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 & Esc (amongst others) will exit editing in this field, Shift+Enter will allow newlines.
  • 'Country' columns shows using 'richSelect' for a complex object - the cellRenderer takes care of only rendering the country name.

Angular Cell Editing

This section explains how to utilise ag-Grid cellEditors using Angular 2+. You should read about how Cell Editing works in ag-Grid first before trying to understand this section.

It is possible to provide a Angular cellEditor for ag-Grid to use. All of the information above is relevant to Angular cellEditors. This section explains how to apply this logic to your Angular component.

For an example of Angular cellEditing, see the ag-grid-angular-example on Github.

Specifying a Angular cellEditor

If you are using the ag-grid-angular component to create the ag-Grid instance, then you will have the option of additionally specifying the cellEditors as Angular components.

// create your cellEditor as a Angular component
@Component({
    selector: 'editor-cell',
    template: `
        <div #container class="mood" tabindex="0" (keydown)="onKeyDown($event)">
            <img src="../images/smiley.png" (click)="setHappy(true)" [ngClass]="{'selected' : happy, 'default' : !happy}">
            <img src="../images/smiley-sad.png" (click)="setHappy(false)" [ngClass]="{'selected' : !happy, 'default' : happy}">
        </div>
    `,
    styles: [`
        .mood {
            border-radius: 15px;
            border: 1px solid grey;
            background: #e6e6e6;
            padding: 15px;
            text-align:center;
            display:inline-block;
            outline:none
        }

        .default {
            padding-left:10px;
            padding-right:10px;
            border: 1px solid transparent;
            padding: 4px;
        }

        .selected {
            padding-left:10px;
            padding-right:10px;
            border: 1px solid lightgreen;
            padding: 4px;
        }
    `]
})
class MoodEditorComponent implements AgEditorComponent, AfterViewInit {
    private params:any;

    @ViewChild('container', {read: ViewContainerRef}) container;
    private happy:boolean = false;

    // dont use afterGuiAttached for post gui events - hook into ngAfterViewInit instead for this
    ngAfterViewInit() {
        this.container.element.nativeElement.focus();
    }

    agInit(params:any):void {
        this.params = params;
        this.setHappy(params.value === "Happy");
    }

    getValue():any {
        return this.happy ? "Happy" : "Sad";
    }

    isPopup():boolean {
        return true;
    }

    setHappy(happy:boolean):void {
        this.happy = happy;
    }

    toggleMood():void {
        this.setHappy(!this.happy);
    }

    onKeyDown(event):void {
        let key = event.which || event.keyCode;
        if (key == 37 ||  // left
            key == 39) {  // right
            this.toggleMood();
            event.stopPropagation();
        }
    }
}
// then reference the Component in your colDef like this
colDef = {
        headerName: "Mood",
        field: "mood",
        // instead of cellEditor we use cellEditorFramework
        cellEditorFramework: MoodEditorComponent,
        // specify all the other fields as normal
        editable: true,
        width: 150
    }
}

Your Angular components need to implement AgEditorComponent.

By using colDef.cellEditorFramework (instead of colDef.cellEditor) the grid will know it's an Angular component, based on the fact that you are using the Angular version of ag-Grid.

Angular Parameters

Your Angular components need to implement AgEditorComponent. The ag Framework expects to find the agInit method on the created component, and uses it to supply the cell params.

Angular Methods / Lifecycle

All of the methods in the ICellEditor interface described above are applicable to the Angular Component with the following exceptions:

  • init() is not used. Instead implement the agInit method (on the AgRendererComponent interface).
  • destroy() is not used. Instead implement the AngularOnDestroy interface (ngOnDestroy) for any cleanup you need to do.
  • getGui() is not used. Instead do normal Angular magic in your Component via the Angular template.
  • afterGuiAttached() is not used. Instead implement AfterViewInit (ngAfterViewInit) for any post Gui setup (ie to focus on an element).

All of the other methods (isPopup(), getValue(), isCancelBeforeStart(), isCancelAfterEnd() etc) should be put onto your Angular component and will work as normal.

Example: Cell Editing using Angular Components

Using Angular Components in the Cell Editors, illustrating keyboard events, rendering, validation and lifecycle events.

React Cell Editing

This section explains how to utilise ag-Grid cellEditors using React. You should read about how Cell Editing works in ag-Grid first before trying to understand this section.

It is possible to provide a React cellEditor for ag-Grid to use. All of the information above is relevant to React cellEditors. This section explains how to apply this logic to your React component.

For an example of React cellEditing, see the ag-grid-react-example on Github. In the example, the 'name' column uses a React cellEditor.

Specifying a React cellEditor

If you are using the ag-grid-react component to create the ag-Grid instance, then you will have the option of additionally specifying the cellEditors as React components.

// create your cellEditor as a React component
class NameCellEditor extends React.Component {

    // constructor gets the props
    constructor(props) {
        // set initial state to be the value to be edited
        this.state = {value: props.value};
    }

    render() {
    // put in render logic
        return <input type="text" value={this.state.value}></input>;
    }

    // more logic is needed, but enough for now to show the general setup
}

// then reference the Component in your colDef like this
colDef = {

    // instead of cellRenderer we use cellRendererFramework
    cellEditorFramework: NameCellEditor

    // specify all the other fields as normal
    cellRendererFramework: NameCellRenderer     // if you have a React cellRenderer
    headerName: 'Name',
    field: 'firstName',
    ...
}

By using colDef.cellEditorFramework (instead of colDef.cellEditor) the grid will know it's a React component, based on the fact that you are using the React version of ag-Grid.

React Props

The React component will get the 'cellEditor Params' as described above as its React Props. Therefore you can access all the parameters as React Props.

React Methods / Lifecycle

All of the methods in the ICellEditor interface described above are applicable to the React Component with the following exceptions:

  • init() is not used. Instead use the React props passed to your Component.
  • destroy() is not used. Instead use the React componentWillUnmount() method for any cleanup you need to do.
  • getGui() is not used. Instead do normal React magic in your render() method..

All of the other methods (isPopup(), isCancelBeforeStart(), isCancelAfterEnd(), afterGuiAttached() etc) should be put onto your React component and will work as normal.

Example: Cell Editing using React Components

Using React Components in the Cell Editors, illustrating keyboard events, rendering, validation and lifecycle events.

VueJS Cell Editing

This section explains how to utilise ag-Grid cellEditors using VueJS. You should read about how Cell Editing works in ag-Grid first before trying to understand this section.

It is possible to provide a VueJS cellEditor for ag-Grid to use. All of the information above is relevant to VueJS cellEditors. This section explains how to apply this logic to your VueJS component.

For an example of VueJS cellEditing, see the ag-grid-vue-example on Github.

Specifying a VueJS cellEditor

If you are using the ag-grid-vue component to create the ag-Grid instance, then you will have the option of additionally specifying the cellEditors as VueJS components.

A VueJS component can be defined in a few different ways (please see Defining VueJS Components for all the options), but in this example we're going to define our editor as a Single File Component:

// create your cellEditor as a VueJS component
<template>
    <div :ref="'container'" class="mood" tabindex="0" @keydown="onKeyDown">
        <img src="images/smiley.png" @click="onClick(true)" :class="{selected : happy, default : !happy}">
        <img src="images/smiley-sad.png" @click="onClick(false)" :class="{selected : !happy, default : happy}">
    </div>
</template>

<script>
    import Vue from "vue";

    export default Vue.extend({
        data() {
            return {
                happy: false,
                imgForMood: null
            }
        },
        methods: {
            getValue() {
                return this.happy ? "Happy" : "Sad";
            },

            isPopup() {
                return true;
            },

            setHappy(happy) {
                this.happy = happy;
            },

            toggleMood() {
                this.setHappy(!this.happy);
            },

            onClick(happy) {
                this.setHappy(happy);
                this.params.api.stopEditing();
            },

            onKeyDown(event) {
                let key = event.which || event.keyCode;
                if (key == 37 ||  // left
                    key == 39) {  // right
                    this.toggleMood();
                    event.stopPropagation();
                }
            }
        },
        created() {
            this.setHappy(this.params.value === "Happy");
        },
        mounted() {
            Vue.nextTick(() => {
                this.$refs.container.focus();
            });
        }
    })
</script>

<style scoped>
    .mood {
        border-radius: 15px;
        border: 1px solid grey;
        background: #e6e6e6;
        padding: 15px;
        text-align: center;
        display: inline-block;
        outline: none
    }

    .default {
        border: 1px solid transparent !important;
        padding: 4px;
    }

    .selected {
        border: 1px solid lightgreen !important;
        padding: 4px;
    }
</style>

// then reference the Component in your colDef like this
this.colDefs = [
    {
        // specify all the other fields as normal
        headerName: "Mood",
        field: "mood",
        editable: true,
        width: 250,
        // instead of cellEditor we use cellEditorFramework
        cellEditorFramework: MoodEditorComponent
    }

By using colDef.cellEditorFramework (instead of colDef.cellEditor) the grid will know it's a VueJS component, based on the fact that you are using the VueJS version of ag-Grid.

VueJS Parameters

The Grid cell's value will be made available implicitly in a data value names params. This value will be available to you from the created VueJS lifecycle hook.

You can think of this as you having defined the following:

export default {
    data () {
        return {
            params: null
        }
    },
    ...

but you do not need to do this - this is made available to you behind the scenes, and contains the cells value.

VueJS Methods / Lifecycle

All of the methods in the ICellEditor interface described above are applicable to the VueJS Component with the following exceptions:

  • init() is not used. The cells value is made available implicitly via a data field called params.
  • getGui() is not used. Instead do normal VueJS magic in your Component via the VueJS template.
  • afterGuiAttached() is not used. Instead implement the mounted VueJS lifecycle hook for any post Gui setup (ie to focus on an element).

All of the other methods (isPopup(), getValue(), isCancelBeforeStart(), isCancelAfterEnd() etc) should be put onto your VueJS component and will work as normal.

Example: Cell Editing using VueJS Components

Using VueJS Components in the Cell Editors, illustrating keyboard events, rendering, validation and lifecycle events.

Aurelia Cell Editing

This section explains how to utilise ag-Grid cellEditors using Aurelia. You should read about how Cell Editing works in ag-Grid first before trying to understand this section.

It is possible to provide a Aurelia cellEditor for ag-Grid to use. All of the information above is relevant to Aurelia cellEditors. This section explains how to apply this logic to your Aurelia component.

For an example of Aurelia cellEditing, see the ag-grid-aurelia-example on Github.

Specifying a Aurelia cellEditor

// Create your cellEditor as a Aurelia component

// Component View
<template>
  <require from="./mood-editor.css">

  <div class.bind="'mood'" tabindex="0" focus.bind="hasFocus" keydown.trigger="onKeyDown($event)">
    <img src="images/smiley.png" click.delegate="setHappy(true)" class.bind="happy ? 'selected' : 'default'">
    <img src="images/smiley-sad.png" click.delegate="setHappy(false)" class.bind="!happy ? 'selected' : 'default'">
  </div>
</template>

// Component Logic
@customElement('ag-mood-editor')
@inject(Element)
export class NumericEditor extends BaseAureliaEditor {
  params: any;

  @bindable() happy: boolean = false;
  @bindable() hasFocus: boolean = false;

  element: any;

  constructor(element) {
    super();

    this.element = element;
  }

  attached(): void {
    this.setHappy(this.params.value === "Happy");
    this.hasFocus = true;
  }

  getValue(): any {
    return this.happy ? "Happy" : "Sad";
  }

  isPopup(): boolean {
    return true;
  }

  setHappy(happy: boolean): void {
    this.happy = happy;
  }

  toggleMood(): void {
    this.setHappy(!this.happy);
  }

  onKeyDown(event): void {
    let key = event.which || event.keyCode;
    if (key == 37 ||  // left
      key == 39) {  // right
      this.toggleMood();
      event.stopPropagation();
    }
  }
}

// then reference the Component in your column definitions like this
<ag-grid-aurelia #agGrid style="width: 100%; height: 100%;" class="ag-fresh"
                 grid-options.bind="gridOptions">
  <ag-grid-column header-name="Mood" field="mood" width.bind="150" editable.bind="true">
    <ag-editor-template>
      <ag-mood-editor></ag-mood-editor>
    </ag-editor-template>
  </ag-grid-column>
</ag-grid-aurelia>

Your Aurelia components should implement BaseAureliaEditor.

Aurelia Parameters

All of the other methods (isPopup(), getValue(), isCancelBeforeStart(), isCancelAfterEnd() etc) should be put onto your Aurelia component and will work as normal.