我正在使用Def Extreme Grid,我希望每行都有一个按钮,这样就可以更改行的数据。在buttonClick上的示例中,我想将汽车品牌重置为空字符串。由于具有按钮的自定义单元格在类外部定义了网格,我不知道如何访问状态。
const Cell = props => {
if (props.column.name === "city") {
return (
<td>
<button>Reset car brand</button>
</td>
);
}
return <Table.Cell {...props} />;
};
答案 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 :(得分: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
中。
如果您希望它运行: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;