如何防止 ag-grid-react cellEditor 组件中 "Enter" 按键的事件传播?

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

我的问题主要围绕文档 w.r.t 中的 this statement。反应组件:

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.

我知道 cellEditor 参数作为传递给组件的反应版本的道具存在,但我似乎无法找到如何附加到 onKeyDown 中指定的方法文档。在我的 cellEditor 的构造函数中,onKeyDown 函数存在并匹配列定义中 cellEditorParams 中指定的 onKeyDown(如果存在)。

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,我试图在按下 enter 时将焦点和 select 设为下一个单元格,而不仅仅是 Tab。我已经能够从 this.props.api.rowRenderer 处的 rowRenderer 中提取我需要的 rowIndexcolumn 属性,然后我将其用作:

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

我的问题是默认情况下在何处阻止“Enter”键的事件传播。

下面是我的Cell Editor和使用方法。

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

我从ag-grid的文档中发现,"grid-api"是由React组件的onGridRead()回调提供的。 下面的api函数可以帮助你为keyPress注册一个事件。

addEventListener(eventType, listener)

试试这样的东西:

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

keyPressEventHandlerCallback=(e)=>{
    ...handler code here
}

向网格容器添加侦听器以捕获按下键。

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
    }
}

目的是在您的 cellRenderer 中捕获 'enter' 按下,如下所示:

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 中发生了不同的事情,那么我不知道 :(

不幸的是,none 提供的答案实际上能够阻止原生 ag-grid 导航事件的传播,尽管停止了事件传播、立即传播并阻止了默认设置。

我在未知区域的某个地方使用 react ag-grid,导航元素正在劫持所有内容。我知道这一点,因为我在按照此线程中的建议添加侦听器后向源中的 renderedCell.ts 添加了一个控制台,并在侦听器的控制台输出之前先输出了 renderedCell 的控制台。

我最终选择了分叉 ag-grid 并调整 onKeyDown 的简单愚蠢的方法:

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

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

路易斯

我最后做的是更改 afterGuiAttached 中的一行(示例 LargeTextCellEditor.prototype.afterGuiAttached),以便从超时调用 this.textarea.focus。 (我还没有进一步寻找问题的根源,但这对我现在有用)

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

v13.2.0 开始,ag-grid 有一个 suppressKeyboardEvent 回调,可以将其添加到列定义中以自定义默认键盘导航。您可以找到文档和示例 here in the official docs