Reputation: 3129
I have a react admin project and have implemented a custom button for the List view passed into the bulkActionButtons
attribute as described by the docs here: https://marmelab.com/react-admin/List.html#bulk-action-buttons
const BulkUserActions = props => (
<MakeAdminButton {...props}/>
);
const UserList = props => (
<List {...props} bulkActionButtons={<BulkUserActions/>}>
<Datagrid rowClick="show">
<TextField source="id"/>
<EmailField source="email"/>
</Datagrid>
</List>
);
The MakeAdminButton
handles the click and performs the update that I need. The missing piece of the puzzle is how to deselect the list items after the action is completed. The props.selectedIds
is protected so I am unable to simply set this to an empty array after completing my logic.
Question is how to unset props.selectedIds
or other method for deselecting the list items on completion.
const MakeAdminButton = withStyles(styles)(class MakeAdminButton extends React.Component {
handleAction = () => {
//does the stuff as required using this.props.selectedIds
//what to return to unset this.props.selectedIds
};
render () {
return <Button variant="contained"
color="primary"
onClick={this.handleAction}
<AdminIcon/>
</Button>;
}
});
Upvotes: 2
Views: 3796
Reputation: 927
React Admin provide ways of doing it. On v3 directly with useUnselectAll or on onSuccess callback of useMutation, useUpdateMany and useDataProvider hooks. On v2 with dataProvider fourth argument of withDataProvider decorator or seting meta.onSuccess.unselectAll to true of custom redux actions, or automatically with crudUpdateMany, or options prop of Mutation component.
For v2 with crudUpdateMany, goto
Mike Miller answer.
Working examples:
https://codesandbox.io/s/exciting-firefly-dd1ni?file=/src/App.js
v3:
const UnselectAllButtonV3Hook = props => {
const unselectAll = useUnselectAll();
return (
<Button
onClick={() => {
unselectAll(props.resource);
}}
>
Unselect all with v3 hook
</Button>
);
};
https://marmelab.com/react-admin/doc/3.5/Actions.html#handling-side-effects-in-usedataprovider
useUpdateMany/useDataProvider/useMutation hooks, onSuccess callback calling unselectAll()
from useUnselectAll()
const MakeAdminButtonV3 = props => {
const refresh = useRefresh();
const unselectAll = useUnselectAll();
const [makeAdmin, { loading }] = useUpdateMany(
props.resource,
props.selectedIds,
{ isAdmin: true },
{
onSuccess: () => {
unselectAll(props.resource);
refresh();
}
}
);
//OR
const dataProvider = useDataProvider();
const makeAdmin2 = () => {
dataProvider.updateMany(
props.resource,
{ ids: props.selectedIds, data: { isAdmin: true } },
{
onSuccess: () => {
unselectAll(props.resource);
refresh();
}
}
);
};
//OR
const [makeAdmin3, { loading3 }] = useMutation(
{
type: "updateMany",
resource: props.resource,
payload: { ids: props.selectedIds, data: { isAdmin: true } }
},
{
onSuccess: () => {
unselectAll(props.resource);
refresh();
}
}
);
return (
<Button onClick={makeAdmin3} disabled={loading3}>
Make Admin with V3 dataProvider hooks
</Button>
);
};
https://marmelab.com/react-admin/doc/3.5/Actions.html#usemutation-hook
https://marmelab.com/react-admin/doc/3.5/Actions.html#usedataprovider-hook
https://marmelab.com/react-admin/doc/3.5/Actions.html#specialized-hooks
V2 examples also work on v3, but Mutation and withDataProvider is legacy, with a small change while using dataProvider directly, since dataProvider api on v3 changed.
v2:
withDataProvider:
const UnmakeAdminButtonWithWithDataProvider = withDataProvider(
class extends React.Component {
handleClick = () => {
this.props.dataProvider(
UPDATE_MANY,
"users",
{ ids: this.props.selectedIds, data: { isAdmin: false } },
{ onSuccess: { unselectAll: true, refresh: true } }
);
};
render() {
return (
<Button onClick={this.handleClick}>
Unmake Admin with withDataProvider
</Button>
);
}
}
);
https://marmelab.com/react-admin/doc/2.9/Actions.html#handling-side-effects
custom redux action:
import { connect } from 'react-redux';
const MAKE_ADMIN = "MAKE_ADMIN";
const makeAdmin = ids => ({
type: MAKE_ADMIN,
payload: { ids, data: { isAdmin: true } },
meta: {
fetch: UPDATE_MANY,
resource: "users",
onSuccess: { unselectAll: true, refresh: true }
}
});
const MakeAdminButtonWithCustomAction = connect(
null,
{ makeAdmin }
)(
class extends React.Component {
handleClick = () => {
this.props.makeAdmin(this.props.selectedIds);
};
render() {
return (
<Button onClick={this.handleClick}>
Make Admin With Custom Redux Action
</Button>
);
}
}
);
https://marmelab.com/react-admin/doc/2.9/Actions.html#adding-side-effects-to-actions
Mutation component:
const MakeAdminMutationV2 = props => (
<Mutation
type="updateMany" //{UPDATE_MANY}
resource={props.resource}
payload={{ ids: props.selectedIds, data: { isAdmin: true } }}
options={{
onSuccess: {
unselectAll: true,
refresh: true
}
}}
>
{approve => <Button onClick={approve}>Make admin with Mutation</Button>}
</Mutation>
);
https://marmelab.com/react-admin/doc/2.9/Actions.html#query-and-mutation-components
Upvotes: 3
Reputation: 3129
The solution is to call a bulk helper function from react admin:
class MakeAdminButton extends React.Component {
handleAction = () => {
const { basePath, crudUpdateMany, resource, selectedIds } = this.props;
//custom code goes in here...
//calling this function triggers the unset and closes the toolbar
crudUpdateMany(resource, selectedIds, { isAdmin: true }, basePath);
};
render () {
return <Button label="Make Admin" onClick={this.handleAction}>
<AdminIcon/>
</Button>;
}
};
const BulkUserActions = connect(undefined, { crudUpdateMany })(MakeAdminButton);
const UserList = props => (
<List {...props} bulkActionButtons={<BulkUserActions/>}>
<Datagrid>
<TextField source="id"/>
<EmailField source="email"/>
<BooleanField source="isAdmin" label="Admin" />
</Datagrid>
</List>
);
An example is shown on this page if I had bothered to read it properly: https://github.com/marmelab/react-admin/blob/master/docs/List.md#bulk-action-buttons
Upvotes: -1
Reputation: 1277
Set up some meta data for each time you click the checkbox, so it injects true or false into the array like:
listData = {
...
isChecked : true
}
Then inside the function that handles the bulk operations, add a [listData].filter( )
, (lodash filter is faster), to check and see which isChecked === true
, and then set them to false, and update the value={bool}
attribute on the checkbox input tag.
Upvotes: 0