ReactJS: AG-GRID: динамически назначаемый редактор ячеек на основе метаданных - PullRequest
0 голосов
/ 12 июня 2019

Я хочу применить редактор ячеек динамически на основе метаданных. Например, если строка определена как числовая (то есть строка, содержащая целочисленные данные), я хочу использовать редактор чисел. Для Даты, Редактора Даты и т.д ...

Я буду знать только во время выполнения определение каждой строки, и поскольку каждая строка может содержать свой собственный тип данных, применение редактора ячеек на уровне столбца не будет работать, если редактор зависит от типа данных (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}
    />

для применения изменения Cell Editor в обработчике событий ниже:

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 уже было установлено дважды: нажатие на ячейку будет означать 3-е + время.

========== РЕДАКТИРОВАТЬ ==========

Я обнаружил, что резкое изменение структуры cols заставит приложение применить изменения в Cell Editor. Например, при копировании моего columnDefs в новый массив, и я нарезаю несколько столбцов вместо того, чтобы взять весь массив:

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

когда я устанавливаю состояние столбца,

this.setState({ columnDefs: cols });

мой выбор редактора вступает в силу.

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

Другой подход, с которым у меня не получилось, - принудительно обновить, используя либо:

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

но ни один из них не кажется здесь эффективным.

Я ценю ваши отзывы - спасибо.

...