如何在DevExtreme React Grid中的单元格内添加按钮?

时间:2018-06-13 19:47:56

标签: reactjs devextreme

我正在使用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} />;
};

3 个答案:

答案 0 :(得分:4)

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

import React from 'react'
import PropTypes from 'prop-types'
import IconButton from '@material-ui/core/IconButton'
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';
const TABLE_HEADING_TYPE = 'heading';

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

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

要使用此插件,只需在Table插件声明后将其包含在Grid定义中:

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
  4. 希望这有帮助。

答案 1 :(得分:3)

我已经分叉了你的沙箱代码,并对它做了一些补充。希望这就是你要找的东西。以下是相同的代码。希望这会有所帮助。

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"));

答案 2 :(得分:0)

我制作了一个插件,该插件可与开发极端反应网格版本2和类型脚本一起使用。 整个插件位于ActionColumns.tsx中。

结果如下所示: Two columns with an action in dev extreme react grid

如果您希望它运行: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;