WiXSL
WiXSL

Reputation: 707

react-admin: Access <List/> records from bulkActions

The docs state that bulkActions don't get selected records of a List component, just the selected ids, but i need to check a specific field in each selected record from a button's click handler of the bulkActionsButtons.

Any ideas of how this could be achieved?

Upvotes: 3

Views: 2050

Answers (4)

Mathieu Rios
Mathieu Rios

Reputation: 386

I found out that by using the useListContext, you can access all records from the list. Then you just have to filter your records with the selected ids and check your specific field.

Upvotes: 0

chichilatte
chichilatte

Reputation: 1808

Just to expand on @Sudharsan-Ravikumar's answer, the ref solution didn't work in my situation either (react-admin 3.14.1, using classes instead of functions+hooks mostly). I used aside like this...

import React, {Fragment} from 'react';
import {List, Datagrid, TextField, useListContext} from 'react-admin';
import Button from '@material-ui/core/Button';
import AccountTreeIcon from '@material-ui/icons/AccountTree'

import dataProvider from './dataProvider';

export class MyList extends React.Component {

    list = null

    handleStartMyTask = async () => {
        if (!this.list || !this.list.ids || this.list.ids.length===0) return;
        // console.log(`LIST DATA:`, this.list.data)

        try {
            const result = await dataProvider.doMyRemoteTask(this.list.data)
            console.log(result)
        }
        catch(err) {
            console.log()
        }

    }


    /** 
     * This was the only way i could figure out how to get the list details.
     * That is, the props you get access to when you do useListContext().
     * Refs didn't work.
     */
    Aside = () => {
        this.list = useListContext()
        // We don't actually want an aside component for the list.
        return null;
    }


    render = () => {
        return <Fragment>

            /* A little card outside the list with some useful buttons */
            <div class="card">
                <Button 
                    variant="outlined" color="primary" size="medium"  
                    onClick={this.handleStartMyTask}
                >
                    <AccountTreeIcon/>&nbsp;&nbsp;Start my task now!
                </Button>
            </div>

            <List {...this.props} aside={<this.Aside/>} >
                <Datagrid>
                    <TitleField source="title" />
                </Datagrid>
            </List>

        </Fragment>
    }

}

Probably absolute heresy to hooks dorks but life is short!

Upvotes: 1

Sudharsan Ravikumar
Sudharsan Ravikumar

Reputation: 433

I used the aside prop that is passed to the List component. Your ref based solution did not work for me.

https://marmelab.com/react-admin/List.html#aside-component

Check the above link. The component passed as the aside prop to List component receives selectedIds and the data as part of the props.

Upvotes: 1

WiXSL
WiXSL

Reputation: 707

Ok, this is what i did and it works. A combination of a render prop and a ref. Please if anyone have a better idea, please let me now.

import React, {Component} from 'react';
import {
    List,
    Datagrid,
    TextField,
    Button
} from 'react-admin';

class MyBulkButtons extends Component {
    handleClick = () => {
        const {getSelectedRecords} = this.props;
        const records = getSelectedRecords();
        const selectedRecords = records.filter(i => i.title === 'Extra action!');

        this.processExtraActions(selectedRecords);
    };

    processExtraActions(selectedRecords) {
        //...
    }

    render() {
        return (
          <Button onClick={this.handleClick} label={"Check for extra actions"}/>
        );
    }
}

export class MyList extends Component {
    constructor(props) {
        super(props);
        this.myDataGrid = React.createRef();
    }

    getSelectedRecords() {
        const gridProps = this.myDataGrid.current.props;

        return gridProps.selectedIds.map(id => gridProps.data[id]);
    }

    render() {
        return (
          <List {...this.props}
                bulkActionButtons={<MyBulkButtons getSelectedRecords={this.getSelectedRecords.bind(this)}/>}>

              <Datagrid ref={this.myDataGrid}>
                  <TextField source="id"/>
                  <TextField source="title"/>
              </Datagrid>
          </List>
        );
    }
}

Upvotes: 2

Related Questions