I'm using the Def Extreme Grid and I want to have a button in each row, making it possible to change the data of a row. In the example on buttonClick I want to reset the car brand to an empty string. As the custom cell with the button is defined outside the class with the grid I don't know how to acces the state.
const Cell = props => {
if (props.column.name === "city") {
return (
<td>
<button>Reset car brand</button>
</td>
);
}
return <Table.Cell {...props} />;
};
I'm currently working with react grid from DevExtreme and I've faced a similar problem but followed a different solution. What I did was create a new Plugin in order to add a new column called "ActionsColumn". You can pass both nodes and associated callbacks to the plugin. The minimum code would be something like this (sorry, not tested):
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,
};
You simply check whether you are in a header row or a regular table row and you just add a header or the actions you defined respectively.
In order to use this plugin, simply include it in your Grid definition after the Table plugin declaration:
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>
)
}
The way I came up with this solution is quite straightforward:
Hope this helps.