How to prevent event propagation for "Enter" key press in ag-grid-react cellEditor component?

buddyp450 picture buddyp450 · Nov 23, 2016 · Viewed 8k times · Source

My question primarily revolves around this statement in the docs w.r.t. the react component:

cellEditor Params

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.

I understand that the cellEditor params exist as the props being passed to the react version of the component but I can't seem to find how to attach to onKeyDown as specified in the docs. In my constructor for my cellEditor the onKeyDown function exists and matches the onKeyDown specified in cellEditorParams inside my column definition (if it exists).

constructor(props) {
  super(props);
  // console.log(typeof props.onKeyDown == 'function') => 'true'
}

But it's never reached if it simply exists in the component

onKeyDown(event) {
  console.log('not reached');
}

It does get invoked if I put onKeyDown={this.props.onKeyDown} inside of a top level wrapping div around my input but it still doesn't catch the "Enter" press.

I tried listening to the cell containing my custom cell editor

this.props.eGridCell.addEventListener('keyup', (event) => {
  console.log(event.keyCode === 13)
})

Which does capture the enter press but it seems to unmount when enter is pressed before I can capture the final enter press inside the field? I've seen behavior where this doesn't work too so I'm very confused.

I currently have a simple cell editor MyCellEditor that I am trying to make focus and select the next cell when enter is pressed in addition to just tab. I already have the ability to extract the rowIndex and column properties I need from the rowRenderer at this.props.api.rowRenderer which I then use like:

this.props.api.rowRenderer.moveFocusToNextCell(rowIndex, column, false, false, true);

My issue is where to prevent the event propagation by default from the "Enter" press.

Below is my Cell Editor and the usage.

import React from 'react';
import _ from 'lodash';

class MyCellEditor extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: props.value,
    };
  }

  getValue() {
    return this.state.value;
  }

  isPopup() {
    return false;
  }

  isCancelBeforeStart() {
    return false;
  }

  afterGuiAttached() {
    const eInput = this.input;
    eInput.focus();
    eInput.select();
  }

  onKeyDown(event) {
    // Never invoked!
  }

  onChangeListener = (e) => {
    this.setState({ value: e.target.value });
  }

  render() {
    return (
      <input
        ref={(c) => { this.input = c; }}
        className="ag-cell-edit-input"
        type="text"
        value={this.state.value}
        onChange={this.onChangeListener} />
    );
  }
}
export default MyCellEditor;

Column definition:

columnDefs = [{
    headerName: 'CustomColumn',
    field: 'customField',
    editable: true,
    cellClass: 'grid-align ag-grid-shop-order-text',
    sortable: false,
    cellEditorFramework: MyCellEditor,
    // Do I need cellEditorParams?
    cellEditorParams: {
      // onKeyDown: (event) => console.log('does not output')
    }
  },
  ...
}

React:

<AgGridReact
  columnDefs={columnDefs}
  rowData={this.props.rows}
  enableColResize="false"
  rowSelection="single"
  enableSorting="false"
  singleClickEdit="true"
  suppressMovableColumns="true"
  rowHeight="30"
  // onKeyDown also does nothing here
  onGridReady={this.onGridReady}
  onGridResize={() => console.log('grid resized')}
  onColumnResize={() => console.log('column resized')} />

Answer

Luis Palacios picture Luis Palacios · Dec 3, 2016

@buddyp450, had exactly same problem and created an issue under ag-grid gitgub, however found workaround few minutes later, you can change key code to 13 in my example and works perfect :)

https://github.com/ceolter/ag-grid/issues/1300

export default class PATableCellEditor extends Component {
    constructor(props) {
        super(props);
        :
    }
    :
    afterGuiAttached() {
        // get ref from React component
        let eInput = this.refs.textField;
        :
        // Add a listener to 'keydown'
        let self = this;
        eInput.addEventListener('keydown', function (event) {
            self.myOnKeyDown(event)
        });
        :
    }
    :
    // Stop propagating 'left'/'right' keys
    myOnKeyDown(event) {
        let key = event.which || event.keyCode;
        if (key === 37 ||  // left
            key === 39) {  // right
            event.stopPropagation();
        }
    }
    :

Luis