【问题标题】:How to add a button inside a cell in the DevExtreme React Grid?如何在 DevExtreme React Grid 的单元格内添加按钮?
【发布时间】:2018-06-13 19:47:55
【问题描述】:

我正在使用Def Extreme Grid,我希望在每一行中都有一个按钮,从而可以更改一行的数据。在 buttonClick 的示例中,我想将汽车品牌重置为空字符串。由于带有按钮的自定义单元格是在带有网格的类之外定义的,我不知道如何访问状态。

Code Pen

const Cell = props => {
  if (props.column.name === "city") {
    return (
      <td>
        <button>Reset car brand</button>
      </td>
    );
  }

  return <Table.Cell {...props} />;
};

【问题讨论】:

    标签: reactjs devextreme


    【解决方案1】:

    我目前正在使用 DevExtreme 的反应网格,我遇到了类似的问题,但采用了不同的解决方案。我所做的是创建一个新插件以添加一个名为“ActionsColumn”的新列。您可以将节点和关联的回调传递给插件。最低代码是这样的(抱歉,未测试):

    import React from 'react'
    import PropTypes from 'prop-types'
    import IconButton from '@material-ui/core/IconButton'
    import { TABLE_HEADING_TYPE } from '@devexpress/dx-grid-core'
    import {Getter, Template, Plugin} from '@devexpress/dx-react-core'
    import {
        Table,
    } from '@devexpress/dx-react-grid-material-ui'
    
    const pluginDependencies = [
        {name: 'Table'},
    ];
    
    const ACTIONS_COLUMN_TYPE = 'actionsColumnType';
    
    function tableColumnsWithActions(tableColumns, width) {
        return [...tableColumns, {key: ACTIONS_COLUMN_TYPE, type: ACTIONS_COLUMN_TYPE, width: width}];
    }
    
    function isHeadingActionsTableCell(tableRow, tableColumn) {
        return tableRow.type === TABLE_HEADING_TYPE && tableColumn.type === ACTIONS_COLUMN_TYPE;
    }
    
    function isActionsTableCell(tableRow, tableColumn) {
        return tableRow.type !== TABLE_HEADING_TYPE && tableColumn.type === ACTIONS_COLUMN_TYPE;
    }
    
    export class ActionsColumn extends React.PureComponent {
        render() {
            const {
                actions,
                width,
            } = this.props;
            const tableColumnsComputed = ({tableColumns}) => tableColumnsWithActions(tableColumns, width);
    
            return (
                <Plugin
                    name="ActionsColumn"
                    dependencies={pluginDependencies}
                >
                    <Getter name="tableColumns" computed={tableColumnsComputed}/>
    
                    <Template
                        name="tableCell"
                        predicate={({tableRow, tableColumn}) =>
                        isHeadingActionsTableCell(tableRow, tableColumn)}
                    >
                        <Table.Cell>Actions Column</Table.Cell>
                    </Template>
                    <Template
                        name="tableCell"
                        predicate={({tableRow, tableColumn}) => isActionsTableCell(tableRow, tableColumn)}
                    >
                        {params => (
                            <Table.Cell {...params} row={params.tableRow.row}>
                                {actions.map(action => {
                                    const id = params.tableRow.row.id;
                                    return (
                                        <IconButton onClick={() => action.action(id)}>
                                            {action.icon}
                                        </IconButton>
                                    )
    
                                })}
                           </Table.Cell>
                        )}
                    </Template>
                </Plugin>
            );
        }
    }
    ActionsColumn.propTypes = {
        actions: PropTypes.arrayOf(PropTypes.PropTypes.shape({
            icon: PropTypes.node,
            action: PropTypes.func.isRequired
        })).isRequired,
        width: PropTypes.number
    };
    ActionsColumn.defaultProps = {
        width: 240,
    };
    

    您只需检查您是在标题行还是常规表格行中,然后添加标题或您分别定义的操作。

    为了使用这个插件,只需在表格插件声明之后将它包含在您的网格定义中:

    render() {
        const {columns, rows} = this.state;
        const actions = [
            {
                icon: <DeleteIcon/>,
                action: doAlert
            },
            {
                icon: <EditIcon/>,
                action: id => alert('edit id: ' + id)
            }
        ];
    
        return (
            <Grid rows={rows} columns={columns} getRowId={getRowId}>
                <Table/>
                <TableHeaderRow/>
                <ActionsColumn actions={actions}/>
            </Grid>
        )
    }
    

    我想出这个解决方案的方法非常简单:

    1. 阅读 Oliver Sturm 的“DevExtreme React Grid - Blog Series
    2. 阅读React Core 文档。
    3. 查看 GitHub 上现有的 table-edit-column 源代码:herehere

    希望这会有所帮助。

    【讨论】:

    • 是否有与此插件一起使用的列、行示例集?
    • params.tableRow.row 未定义
    • 我修复了代码并提交了修改以供审核。它运行良好。谢谢
    【解决方案2】:

    我已经分叉了您的沙盒代码并对其进行了一些补充。希望这就是你要找的。下面是相同的代码。希望这会有所帮助。

    import React from "react";
    import { render } from "react-dom";
    import Paper from "@material-ui/core/Paper";
    import // State or Local Processing Plugins
    "@devexpress/dx-react-grid";
    import {
        Grid,
        Table,
        TableHeaderRow
    } from "@devexpress/dx-react-grid-material-ui";
    
    class App extends React.PureComponent {
        constructor(props) {
            super(props);
    
            this.state = {
                columns: [
                    { name: "name", title: "Name" },
                    { name: "sex", title: "Sex" },
                    { name: "city", title: "City" },
                    { name: "car", title: "Car" },
                    { name: "action", title: "action" }
                ],
                rows: [
                    {
                        sex: "Female",
                        name: "Sandra",
                        city: "Las Vegas",
                        car: "Audi A4",
                        action: this.addResetBtn.call(this, { index: 0 })
                    },
                    { sex: "Male", name: "Paul", city: "Paris", car: "Nissan Altima" },
                    { sex: "Male", name: "Mark", city: "Paris", car: "Honda Accord" },
                    { sex: "Male", name: "Paul", city: "Paris", car: "Nissan Altima" },
                    { sex: "Female", name: "Linda", city: "Austin", car: "Toyota Corolla" },
                    {
                        sex: "Male",
                        name: "Robert",
                        city: "Las Vegas",
                        car: "Chevrolet Cruze",
                        action: this.addResetBtn.call(this, { index: 5 })
                    },
                    { sex: "Female", name: "Lisa", city: "London", car: "BMW 750" },
                    { sex: "Male", name: "Mark", city: "Chicago", car: "Toyota Corolla" },
                    {
                        sex: "Male",
                        name: "Thomas",
                        city: "Rio de Janeiro",
                        car: "Honda Accord"
                    },
                    { sex: "Male", name: "Robert", city: "Las Vegas", car: "Honda Civic" },
                    { sex: "Female", name: "Betty", city: "Paris", car: "Honda Civic" },
                    {
                        sex: "Male",
                        name: "Robert",
                        city: "Los Angeles",
                        car: "Honda Accord"
                    },
                    {
                        sex: "Male",
                        name: "William",
                        city: "Los Angeles",
                        car: "Honda Civic"
                    },
                    { sex: "Male", name: "Mark", city: "Austin", car: "Nissan Altima" }
                ]
            };
        }
    
        addResetBtn = ({ index }) => {
            return (
                <button
                    className="btn"
                    onClick={this.handleResetClick.bind(this, { index: index })}
                >
                    Reset
                </button>
            );
        };
    
        handleResetClick = ({ index }) => {
            const updatedRows = [...this.state.rows];
            updatedRows[index].car = "";
            this.setState({ rows: updatedRows });
        };
    
        render() {
            const { rows, columns } = this.state;
    
            return (
                <Paper>
                    <Grid rows={rows} columns={columns}>
                        <Table />
                        <TableHeaderRow />
                    </Grid>
                </Paper>
            );
        }
    }
    
    render(<App />, document.getElementById("root"));
    

    【讨论】:

    • 哇,太棒了,你太棒了!你是怎么知道的?网格文档中是否也描述了这一点?
    • 不确定它是否在文档中。但是,这对我来说更有意义。否则,这还取决于您如何将日期注入状态。你可以让这段代码更干净。 :+1:
    【解决方案3】:

    我制作了一个插件,该插件可与 devextreme react grid 的第 2 版一起使用,并且...与类型脚本一起使用。 整个插件在ActionColumns.tsx

    结果如下所示:

    如果你想看到它运行:https://codesandbox.io/s/m6yve

    这里是如何使用它:

    import React from 'react';
    import {
      Grid,
      Table,
      TableHeaderRow,
      Toolbar
    } from '@devexpress/dx-react-grid-material-ui';
    import { Paper } from '@material-ui/core';
    import customers, { IRowType } from "./data";
    import { Column } from '@devexpress/dx-react-grid';
    import { ActionColumns, IActionColumn } from './ActionColumns';
    import MoreVertIcon from '@material-ui/icons/MoreVert';
    import RefreshIcon from '@material-ui/icons/Refresh';
    
    interface IAppState {
      columns: Column[];
      rows: IRowType[];
      actionColumns: IActionColumn[];
    }
    
    class App extends React.PureComponent<any, IAppState> {
      constructor(props: any) {
        super(props);
        this.state = {
          columns: [
            { name: 'ID', title: 'ID' },
            { name: 'CompanyName', title: 'Company Name' },
            { name: 'Address', title: 'Address' },
            { name: 'MakeAction' },
            { name: 'City', title: 'City' },
            { name: 'State', title: 'State' },
            { name: 'Zipcode', title: 'Zip code' },
            { name: 'Open' }
          ],
          actionColumns: [
            { columnName: "Open", label: "Open details", onClick: this.handleClickOpenDetails, icon: <MoreVertIcon /> },
            { columnName: "MakeAction", label: "Make action", onClick: this.handleClickMakeAction, icon: <RefreshIcon /> },
          ],
          rows: customers
        };
      }
      render() {
        const { rows, columns, actionColumns } = this.state;
        return (
          <Paper>
            <Grid rows={rows} columns={columns}>
              <Table />
              <TableHeaderRow />
              <Toolbar />
              <ActionColumns actionColumns={actionColumns} />
            </Grid>
          </Paper>
        );
    
      }
      private handleClickOpenDetails(row: any) {
        console.log("open details", row);
      }
      private handleClickMakeAction(row: any) {
        console.log("make action", row);
      }
    }
    export default App;
    

    这是插件:

    import autobind from "autobind-decorator";
    import * as React from 'react';
    import {
        Template,
        Plugin,
        TemplateConnector,
        Getter,
        Getters,
    } from '@devexpress/dx-react-core';
    import { TableCell, IconButton, Tooltip } from '@material-ui/core';
    import { Table, VirtualTable, TableHeaderRow } from "@devexpress/dx-react-grid-material-ui";
    import { TableColumn } from "@devexpress/dx-react-grid";
    
    function makeDictionary<T>(values: T[], getKey: (value: T) => string) {
        return values.reduce((acc, v) => { acc[getKey(v)] = v; return acc; }, {} as { [key: string]: T });
    }
    
    const pluginDependencies = [
        { name: 'Table' },
    ];
    export interface IActionColumn {
        columnName: string;
        icon: React.ReactElement<any>;
        label?: string;
        onClick: (row: any) => void;
    }
    export interface IActionColumnsProps {
        actionColumns: IActionColumn[];
    }
    
    @autobind
    class ActionColumnsBase extends React.PureComponent<IActionColumnsProps> {
        static ACTION_COLUMN_TYPE = Symbol("ACTION_COLUMN");
        static components = {
            cellComponent: 'Cell',
            headerCellComponent: 'HeaderCell',
            commandComponent: 'Command',
        };
        render() {
            const { actionColumns } = this.props;
            const columnDictionary = makeDictionary(actionColumns, i => i.columnName);
    
            return (
                <Plugin
                    name="ActionColumn"
                    dependencies={pluginDependencies}
                >
                    <Getter name="tableColumns" computed={this.computeColumns.bind(null, columnDictionary)} />
                    <Template name="tableCell" predicate={this.isActionTableHeader.bind(null)}>
                        {(params: any) => (
                            <TemplateConnector>
                                {(getters, actions) => {
                                    return (
                                        <TableCell />
                                    );
                                }}
                            </TemplateConnector>
                        )}
                    </Template>
                    <Template name="tableCell" predicate={this.isActionTableCell.bind(null)}>
                        {(params: any) => (
                            <TemplateConnector>
                                {(getters, actions) => {
                                    const actionColumn = columnDictionary[params.tableColumn.column.name];
                                    const button = (<IconButton
                                        size="small"
                                        aria-label={actionColumn.label}
                                        style={{ verticalAlign: "middle" }}
                                        onClick={actionColumn.onClick.bind(null, params.tableRow.row)} >
                                        {actionColumn.icon}
                                    </IconButton>);
                                    if (actionColumn.label) {
                                        return (<TableCell align="right">
                                            <Tooltip title={actionColumn.label}>
                                                {button}
                                            </Tooltip>
                                        </TableCell>);
                                    }
                                    else {
                                        return (<TableCell align="right">
                                            {button}
                                        </TableCell>);
                                    }
                                }}
                            </TemplateConnector>
                        )}
                    </Template>
                </Plugin>
            );
        }
        private computeColumns(actionColumns: { [key: string]: IActionColumn }, getters: Getters) {
            const tableColumns = getters.tableColumns as TableColumn[];
            const columns = tableColumns.map(tableColumn => {
                if (!tableColumn.column || !actionColumns[tableColumn.column.name]) {
                    return tableColumn;
                }
                return { ...tableColumn, type: ActionColumnsBase.ACTION_COLUMN_TYPE, width: 60 };
            });
            return columns;
        }
        private isActionTableCell(params: any) {
            if ((params.tableRow.type === Table.ROW_TYPE || params.tableRow.type === VirtualTable.ROW_TYPE) && params.tableColumn.type === ActionColumnsBase.ACTION_COLUMN_TYPE) {
                return true;
            }
            return false;
        }
        private isActionTableHeader(params: any) {
            if ((params.tableRow.type === TableHeaderRow.ROW_TYPE) && params.tableColumn.type === ActionColumnsBase.ACTION_COLUMN_TYPE) {
                return true;
            }
            return false;
        }
    }
    export const ActionColumns: React.ComponentType<IActionColumnsProps> & {
        ACTION_COLUMN_TYPE: symbol;
    } = ActionColumnsBase;
    

    【讨论】:

    • 你好代码和框不工作。我想用你写的代码。你能帮帮我吗?
    • 确实,我在codesandbox中误删了样本。好吧,只需复制粘贴上面的内容,我相信没有其他必要了。你不能让它工作吗?
    • 我试过了,但没用。你能帮帮我吗?
    • 是的,两个按钮都可以;他们在控制台中记录事件
    猜你喜欢
    • 1970-01-01
    • 2014-09-06
    • 2019-04-09
    • 2015-02-21
    • 2021-03-31
    • 2015-08-16
    • 2013-05-10
    • 1970-01-01
    • 2012-09-15
    相关资源
    最近更新 更多