Как предотвратить распространение события нажатия клавиши Enter в компоненте ag-grid-react cellEditor?

Мой вопрос в первую очередь вращается вокруг этого утверждения в документах w.r.t. компонент реакции:

Параметры cellEditor

onKeyDown Обратный вызов, чтобы сообщить сетке, что была нажата клавиша - полезно для передачи событий управляющих клавиш (табуляция, стрелки и т. д.) обратно в сетку - однако вам не нужно вызывать это, поскольку сетка уже прослушивает события по мере их распространения. Это требуется только в том случае, если вы предотвращаете распространение события.

Я понимаю, что параметры cellEditor существуют как реквизиты, передаваемые в ответную версию компонента, но я не могу найти, как подключиться к onKeyDown, как указано в документации. В моем конструкторе для моего cellEditor функция onKeyDown существует и соответствует onKeyDown, указанному в cellEditorParams внутри моего определения столбца (если он существует).

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

Но он никогда не достигается, если он просто существует в компоненте

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

Он вызывается, если я помещаю onKeyDown={this.props.onKeyDown} внутри div верхнего уровня, обертывающего мой ввод, но он все равно не ловит нажатие Enter.

Я попытался прослушать ячейку, содержащую мой пользовательский редактор ячеек

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

Какой фиксирует нажатие ввода, но, кажется, отключается при нажатии ввода, прежде чем я смогу зафиксировать последнее нажатие ввода внутри поля? Я видел поведение, когда это тоже не работает, поэтому я очень запутался.

В настоящее время у меня есть простой редактор ячеек MyCellEditor, в котором я пытаюсь сфокусироваться и выбрать следующую ячейку при нажатии клавиши ввода в дополнение к простой вкладке. У меня уже есть возможность извлечь нужные мне свойства rowIndex и column из rowRenderer в this.props.api.rowRenderer, которые я затем использую, например:

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

Моя проблема в том, где предотвратить распространение события по умолчанию при нажатии Enter.

Ниже мой редактор ячеек и его использование.

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;

Определение столбца:

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')
    }
  },
  ...
}

Реагировать:

<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')} />

person buddyp450    schedule 23.11.2016    source источник


Ответы (7)


@ buddyp450, имел точно такую ​​же проблему и создал проблему в ag-grid gitgub, однако через несколько минут был найден обходной путь, вы можете изменить код клавиши на 13 в моем примере и отлично работает :)

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();
        }
    }
    :

Луис

person Luis Palacios    schedule 03.12.2016
comment
Проверено на 6.0.1 и 7.0.0, работает на 6.0.1 и 7.0.0, но в 7.0.0 навигация не работает. Я думаю, это не связано. Я придерживаюсь 6.0.1. - person buddyp450; 04.12.2016

Добавьте слушателя в контейнеры сетки для захвата нажатия клавиши.

onGridReady: {(event) =>  
    event.api.gridPanel.eAllCellContainers.forEach(
        function (container) {
             container.addEventListener('keydown', keyDownFunc);
    });
}
...

Определите слушателя.

function keyDownFunc(e) {
    var key = event.which || event.keyCode;
    if (e.keyCode == 13) { // enter = 13
       // TODO: Handle event
    }
}
person user3294566    schedule 01.12.2016

К сожалению, ни один из предоставленных ответов на самом деле не может предотвратить распространение событий навигации по собственной сетке Ag-grid, несмотря на остановку распространения событий, немедленное распространение и предотвращение распространения по умолчанию.

Где-то в неизвестной мне области с помощью ag-grid элементы навигации захватывают все. Я знаю это, так как я добавил консоль к renderedCell.ts в источнике после добавления слушателей, как предложено в этом потоке, и получил консоль renderedCell до выхода консоли слушателя.

В конце концов, я пошел на просто глупый подход, разветвив ag-grid и настроив onKeyDown:

case Constants.KEY_ENTER:
  // this.onEnterKeyDown();
  // Whatever makes the clients happy amirite?
  this.onTabKeyDown();
  break;
person buddyp450    schedule 02.12.2016

Начиная с v13.2.0, ag-grid имеет suppressKeyboardEvent обратный вызов, который можно добавить к определению столбца для настройки навигации с помощью клавиатуры по умолчанию. Вы можете найти документацию и пример здесь, в официальные документы

person Nupur    schedule 24.10.2017
comment
Я боролся с этим, по какой-то причине stopPropagation мешает моему редактору правильно выполнять свою функцию. Поэтому мне нужно использовать suppressKeyboardEvent, но он вызывается только при навигации, params.editing никогда не бывает истинным. Понятия не имею почему. Возможно ты можешь помочь мне? - person William Wino; 29.05.2019

Из документации ag-grid я обнаружил, что "grid-api" предоставляется обратным вызовом onGridRead () компонента React. Следующая функция api может помочь вам зарегистрировать событие для нажатия клавиши.

addEventListener(eventType, listener)

Попробуйте что-нибудь вроде:

onGridReady = (api)=>{
    api.addEventListener('keyPress', this.keyPressEventHandlerCallback);
}

keyPressEventHandlerCallback=(e)=>{
    ...handler code here
}
person Amoolya S Kumar    schedule 30.11.2016
comment
Это не работает, grid.api.addEventListener("keydown", (ev: any) =>{ }) не запускается при нажатии клавиши; и grid.api.addGlobalListener бесполезен в этой ситуации. Предложение @Luis Palacios работает. - person Artru; 23.01.2017

намерение состоит в том, чтобы вы захватили нажатие клавиши ввода в CellRenderer следующим образом:

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

тогда вы предотвратите распространение от onKeyDownListener. вот как это работает в javascript. если в React что-то происходит иначе, я не знаю :(

person Niall Crosby    schedule 02.12.2016
comment
Я считаю, что вводимая пресса захватывается и перенаправляется куда-то выше по цепочке. Это никогда не касается этого слушателя. - person buddyp450; 03.12.2016

В итоге я изменил строку в afterGuiAttached (например, LargeTextCellEditor.prototype.afterGuiAttached), чтобы this.textarea.focus вызывался по таймауту. (Я еще не искал источник проблемы, но пока это работает для меня)

LargeTextCellEditor.prototype.afterGuiAttached = function () {
        if (this.focusAfterAttached) {
            // this.textarea.focus();
            setTimeout(()=>this.textarea.focus());
        }
    };
person cmbro    schedule 16.12.2016