ReactJS:AG-GRID:基于元数据动态分配单元格编辑器

时间:2019-06-11 22:08:31

标签: reactjs editor ag-grid-react

我希望基于元数据动态地应用单元格编辑器。例如,如果确定该行为数字行(即,保存整数数据的行),我想使用数字编辑器。对于日期,日期编辑器等...

我只会在运行时知道每一行的定义,并且由于每一行都可以保存自己的数据类型,因此如果该编辑器是特定于数据类型的,则无法在列级应用单元格编辑器(I'曾尝试在列级别定义通用编辑器,但觉得我没有足够的能力来做到这一点,也没有足够的“真实”代码来显示示例)。

这是我的组成部分:

import React, { Component } from 'react';
import axios from 'axios';

import { AgGridReact } from 'ag-grid-react';
import 'ag-grid-community/dist/styles/ag-grid.css';
import 'ag-grid-community/dist/styles/ag-theme-balham.css';

import NumericEditor from "./numericEditor.jsx";

import DatePicker from 'react-date-picker'


const API = 'http://localhost:53884/api/UserConfig/UI'
var PARMS = '';

class UserConfig extends Component {
    constructor(props) {
        super(props);

        this.state = {
            columnDefs: [],
            components: null,
            rowData: null,
            isLoading: false,
            error: null,
            config: [],
            heading: "",
            meta: [],
            frameworkComponents: {
                numericEditor: NumericEditor,
                datePicker: DatePicker

            }
        };
        this.onGridReady = this.onGridReady.bind(this);
    }

    onGridReady(params) {
        this.gridApi = params.api;
        this.columnApi = params.columnApi;

        this.gridApi.sizeColumnsToFit();
    }

    componentDidMount() {
        this.setState({ isLoading: true });

        axios.get(API + PARMS)
            .then(fubar => {

                const config = fubar.data.config;
                const headerRow = fubar.data.header;
                const rowData = fubar.data.results;
                const meta = fubar.data.meta;

                this.setState({ heading: "User Configuration: Trade Date " + new Date(config.tradeDate).toLocaleDateString("en-US") });

                var newCols = [
                    { headerName: "", field: "attribute", width: 200, hide: true },
                    { headerName: "", field: "displayName", width: 200, resizable: true, sortable: true, filter: true },
                    { headerName: headerRow.value0, field: "value0", width: 100, resizable: true, editable: true },
                    { headerName: headerRow.value1, field: "value1", width: 100, resizable: true, editable: false },
                    { headerName: headerRow.value2, field: "value2", width: 100, resizable: true, editable: false },
                    { headerName: headerRow.value3, field: "value3", width: 100, resizable: true, editable: false },
                    { headerName: headerRow.value4, field: "value4", width: 100, resizable: true, editable: false },
                    { headerName: headerRow.value5, field: "value5", width: 100, resizable: true, editable: false },
                    { headerName: headerRow.value6, field: "value6", width: 100, resizable: true, editable: false },
                    { headerName: headerRow.value7, field: "value7", width: 100, resizable: true, editable: false },
                    { headerName: headerRow.value8, field: "value8", width: 100, resizable: true, editable: false },
                    { headerName: headerRow.value9, field: "value9", width: 100, resizable: true, editable: false },
                ];

                if (headerRow.value0 === null) newCols[2].hide = true;
                if (headerRow.value1 === null) newCols[3].hide = true;
                if (headerRow.value2 === null) newCols[4].hide = true;
                if (headerRow.value3 === null) newCols[5].hide = true;
                if (headerRow.value4 === null) newCols[6].hide = true;
                if (headerRow.value5 === null) newCols[7].hide = true;
                if (headerRow.value6 === null) newCols[8].hide = true;
                if (headerRow.value7 === null) newCols[9].hide = true;
                if (headerRow.value8 === null) newCols[10].hide = true;
                if (headerRow.value9 === null) newCols[11].hide = true;

                this.setState({ rowData, config, columnDefs: newCols, meta });
            })
            .catch(error => this.setState({
                error,
                isLoading: false
            }));
    }

    onCellEditingStarted = params => {
        const { meta } = this.state;

        const attribute = params.data.attribute;

        var cols = this.state.columnDefs;

        const metaRow = meta.find(item => { return item.attribute === attribute });

        if (metaRow.dataType === "datetime") cols[2].cellEditor = "datePicker";
        if (metaRow.dataType === "int") cols[2].cellEditor = "numericEditor";

        this.setState({ columnDefs: cols });

        //NumericEditor(params);

        //alert('Display Name = ' + metaRow.displayName + ',\n'
        //    + 'Display Order = ' + metaRow.displayOrder + ',\n'
        //    + 'Default Value = ' + metaRow.defaultValue + ',\n'
        //    + 'Data Type = ' + metaRow.dataType + ',\n'
        //    + 'Allow Nulls = ' + metaRow.allowNull);
    };

    render() {
        const { heading, rowData, columnDefs } = this.state;

        return (
            <div className="ag-theme-balham" style={{ height: '500px', width: '800px' }} >
                <h2 style={{ paddingLeft: '32px' }}>{heading}</h2>

                <AgGridReact
                    columnDefs={columnDefs}
                    rowData={rowData}
                    onCellClicked={this.onCellClicked.bind(this)}
                    frameworkComponents={this.state.frameworkComponents}
                />
            </div>

        );
    }
}

export default UserConfig;

我的方法是利用 onCellClicked

    <AgGridReact
        columnDefs={columnDefs}
        rowData={rowData}
        onCellClicked={this.onCellClicked.bind(this)}
        frameworkComponents={this.state.frameworkComponents}
    />

在以下事件处理程序中应用单元格编辑器更改:

onCellClicked = params => {
    const { meta } = this.state;

    const attribute = params.data.attribute;

    var cols = this.state.columnDefs;

    const metaRow = meta.find(item => { return item.attribute === attribute });

    if (metaRow.dataType === "datetime") cols[2].cellEditor = "datePicker";
    if (metaRow.dataType === "int") cols[2].cellEditor = "numericEditor";

    this.setState({ columnDefs: cols });
};

每次单击一个单元格,都会为该单元格行确定数据类型,并修改第[2]列的单元格编辑器以反映该单元格行数据类型。

在我看来,这是一种笨拙的方法,但是我不确定在ReactJS / AG-Grid世界中还能做些什么。

顺便说一句,等到有人能够单击一个单元格时,columnDefs的状态已经设置了两次:单击一个单元格将代表第三次以上的时间。

==========编辑=========

我发现大幅改变cols结构会触发应用程序应用我的Cell Editor更改。例如,当将我的columnDefs复制到新数组中时,我切了几列而不是整个数组:

var cols = this.state.columnDefs.slice(0,8);

设置列状态时

this.setState({ columnDefs: cols });

我的编辑器选择开始了。

当然,我不需要-也不需要-对我的列定义进行如此根本的更改。如果我这样做了,我可能会考虑每次有人单击一个单元格时都添加一个新列,也许是因为目标行数据类型与上次单击的数据类型不同。但这似乎是一种非常糟糕的方法。

我没有成功的另一种方法是使用以下任一方法强制进行更新:

this.forceUpdate();
this.setState({ state: this.state });

但这里似乎都不有效。

感谢您的反馈-谢谢。

1 个答案:

答案 0 :(得分:0)

我只是在寻找类似的东西,而ag-grid文档则讨论了内置此功能。 请参见ag-grid文档(v22.0.0)中的“许多编辑者一栏”部分:https://www.ag-grid.com/javascript-grid-cell-editing/#many-editors-one-column

  

许多编辑者一栏

     

也可以对同一列中的不同行使用不同的编辑器。通常,应用程序可能会检查行内容并相应地选择编辑器。将此colDef.cellEditorSelector设置为一个函数,该函数返回要用作编辑器的组件的名称以及可选的要传入其中的自定义参数

     

传递给此函数的参数与传递给单元格编辑器的参数相同。

     

以下示例说明了如何在同一列中使用不同的编辑器和参数。请注意:

     
      
  • “值”列包含“类型”列中所显示的不同类型的数据(数字/性别/情绪)。
  •   
  • colDef.cellEditorSelector是一个函数,用于根据该行的数据类型返回要用于编辑的组件的名称
  •   
cellEditorSelector:function (params) {

  if (params.data.type === 'age') return {
      component: 'numericCellEditor'
  };

  if (params.data.type === 'gender') return {
      component: 'agRichSelect',
      params: {values: ['Male', 'Female']}
  };

  if (params.data.type === 'mood') return {
      component: 'agRichSelect'
  };

  return null;
}