返回

Rails 7 & AG-Grid: 如何根据其他字段动态控制单元格编辑状态

javascript

在 Rails 7 应用中,我们经常会使用 Stimulus JS 和 AG-Grid 来创建功能丰富的表格。假设我们需要一个表格,其中包含支票号码、备注、付款金额、付款日期和付款方式等可编辑字段。业务需求是根据付款方式来控制支票号码字段是否可以编辑。比如,只有当付款方式选择为“支票”时,支票号码字段才允许用户修改。

一开始,我们可能会直接使用 AG-Grid 提供的 editable 属性,并结合 params.data 来判断当前行的付款方式。代码看起来会像这样:

const columnOptions = {
  columnDefs: {
    cheque_number: { 
      ...EDITABLE_TEXT_COL_DEF, 
      cellClass: 'font-mono', 
      maxWidth: 300, 
      sortable: true, 
      editable: params => params.data.payment_method === 'CHEQUE' 
    },
    // ... 其他字段定义
    payment_method: { 
      cellClass: 'font-mono', 
      maxWidth: 300, 
      sortable: true 
    },
  }
};

这种方法在表格数据第一次加载时确实有效。如果付款方式初始值为“支票”,那么支票号码字段会正常显示为可编辑状态。但是,问题来了,如果用户通过下拉菜单将付款方式从其他选项更改为“支票”,支票号码字段并不会随之变成可编辑状态。这是怎么回事呢?

原因在于 AG-Grid 的 editable 属性只在单元格初始化渲染的时候执行一次判断。当单元格的值发生变化后,AG-Grid 不会自动重新计算 editable 属性的值,因此支票号码字段的状态也就保持不变了。

那么,如何解决这个问题,让支票号码字段能够根据付款方式的变化实时更新编辑状态呢?我们可以利用 AG-Grid 提供的 API 来动态控制单元格的编辑状态。具体来说,我们可以监听 cellValueChanged 事件,当付款方式字段的值发生变化时,手动更新支票号码字段的 editable 属性。

const gridOptions = {
  // ... 其他 Grid 选项
  onCellValueChanged: (params) => {
    if (params.column.colId === 'payment_method') {
      const chequeNumberCell = params.api.getCell(params.rowIndex, 'cheque_number');
      chequeNumberCell.setEditable(params.newValue === 'CHEQUE');
      // 刷新单元格,使其重新渲染
      params.api.refreshCells({ rowNodes: [params.node], force: true }); 
    }
  }
};

在这段代码中,我们首先检查发生变化的单元格是否是付款方式字段。如果是,我们就获取同一行中支票号码字段对应的单元格对象,然后调用 setEditable 方法来设置它的编辑状态。最后,我们调用 refreshCells 方法强制刷新单元格,让修改生效。

通过这种方法,我们就能根据付款方式字段的值动态控制支票号码字段的编辑状态,使表格更具交互性,提升用户体验。

不过,需要注意的是,refreshCells 方法可能会影响表格的性能,尤其是在数据量很大的情况下。如果你的表格数据量非常大,可以考虑使用其他更高效的方式来更新单元格状态,比如使用 AG-Grid 的 rowNode.setDataValue 方法直接修改数据,然后触发单元格的重新渲染。

总而言之,通过监听单元格值变化事件并结合 AG-Grid 提供的 API,我们可以灵活地控制表格中字段的编辑状态,从而构建出更符合业务需求的交互式表格组件。

常见问题及其解答

问题 1:除了 cellValueChanged 事件,还有其他事件可以用来控制单元格的编辑状态吗?

答:是的,AG-Grid 提供了丰富的事件,比如 cellEditingStartedcellEditingStopped,可以根据具体需求选择合适的事件来触发单元格编辑状态的更新。

问题 2:如果表格中有多个字段需要根据其他字段的值来控制编辑状态,应该如何处理?

答:可以将 onCellValueChanged 事件的处理逻辑封装成一个函数,然后根据不同的字段和条件来更新相应的单元格编辑状态。

问题 3:refreshCells 方法会刷新整个表格吗?

答:不会,refreshCells 方法可以指定需要刷新的单元格范围,例如单个单元格、一行单元格或多行单元格。

问题 4:如何提高 refreshCells 方法的性能?

答:可以尽量减少需要刷新的单元格数量,例如只刷新受影响的单元格,而不是刷新整行或整个表格。

问题 5:除了使用 setEditable 方法,还有其他方式可以控制单元格的编辑状态吗?

答:是的,可以通过修改单元格的 CSS 类来控制其编辑状态,例如添加或移除 ag-cell-editable 类。