React Admin - Create and edit in modal
Asked Answered
I

1

8

Following the discussion in https://github.com/marmelab/react-admin/issues/850, did someone manage to make a create / edit form into a modal?

Thanks,

Nicolas

Ironstone answered 12/7, 2018 at 13:9 Comment(11)
I will post a detailed answer when I'll come back from vacations. In the mean time, you can explore this codesandbox: codesandbox.io/s/ypp9ljxqlj. Look at the CommentCreate componentSparky
Lol. I was just looking at the same thing.Britneybritni
@GildasGarcia Thanks! You may want to remove the CancelButton code at PostQuickCreateButton, as it is not used anywhere.Bulldoze
Absolutely! Actually it's an old sandbox because I messed up with my codesandboxes, deleted the wrong one and now I have to rebuild it for a advanced react-admin tutorial blog post. Stay tuned :)Sparky
The article will also show how to build a quick preview inside a drawerSparky
@GildasGarcia thanks, highly looking forward to it!Ironstone
Just updated the codedsandbox :)Sparky
I have only one probleme with this example . It can accept ReferenceArrayInput component .Shurlocke
@GildasGarcia That must be the wrong sandbox. We're looking for create/edit in a modal window, not default values passed to the create form. I mean, I ALSO need that, but that's not the question. Do you have an answer to the modal issue?Britneybritni
Yes, look at the PostReferenceInput used in the CommentCreate componentSparky
@PierreRobentzCassion, I don't get your comment. Please open a new questionSparky
S
13

My previous answer was deleted as it did not contains actual code but only links. Here's a new one with both:

Here's a tutorial showing how to do that: https://marmelab.com/blog/2018/08/27/react-admin-tutorials-custom-forms-related-records.html.

You can find the codesandbox here: https://codesandbox.io/s/ypp9ljxqlj

For example, let's say we want to create a new Post when working a new Comment. You can have a custom PostReferenceInput which will show a button to create a new Post next to the input:

import React, { Fragment } from 'react';
import { Field } from 'redux-form';
import { ReferenceInput, SelectInput } from 'react-admin';

import PostQuickCreateButton from './PostQuickCreateButton';

const PostReferenceInput = props => (
    <Fragment>
        <ReferenceInput {...props}>
            <SelectInput optionText="title" />
        </ReferenceInput>

        <PostQuickCreateButton />
    </Fragment>
);

export default PostReferenceInput;

The PostQuickCreateButton would then be responsible for showing a modal/sidepanel/whatever and handle the actual creation. Note that we use the dataProvider directly so that we know when to close the modal:

import React, { Component, Fragment } from 'react';
import { connect } from 'react-redux';
import { change, submit, isSubmitting } from 'redux-form';
import {
    fetchEnd,
    fetchStart,
    required,
    showNotification,
    crudGetMatching,
    Button,
    SaveButton,
    SimpleForm,
    TextInput,
    LongTextInput,
    CREATE,
    REDUX_FORM_NAME
} from 'react-admin';
import IconContentAdd from '@material-ui/icons/Add';
import IconCancel from '@material-ui/icons/Cancel';
import Dialog from '@material-ui/core/Dialog';
import DialogTitle from '@material-ui/core/DialogTitle';
import DialogContent from '@material-ui/core/DialogContent';
import DialogActions from '@material-ui/core/DialogActions';

import dataProvider from '../dataProvider';

class PostQuickCreateButton extends Component {
    state = {
        error: false,
        showDialog: false
    };

    handleClick = () => {
        this.setState({ showDialog: true });
    };

    handleCloseClick = () => {
        this.setState({ showDialog: false });
    };

    handleSaveClick = () => {
        const { submit } = this.props;

        // Trigger a submit of our custom quick create form
        // This is needed because our modal action buttons are oustide the form
        submit('post-quick-create');
    };

    handleSubmit = values => {
        const {
            change,
            crudGetMatching,
            fetchStart,
            fetchEnd,
            showNotification
        } = this.props;

        // Dispatch an action letting react-admin know a API call is ongoing
        fetchStart();

        // As we want to know when the new post has been created in order to close the modal, we use the
        // dataProvider directly
        dataProvider(CREATE, 'posts', { data: values })
            .then(({ data }) => {
                // Refresh the choices of the ReferenceInput to ensure our newly created post
                // always appear, even after selecting another post
                crudGetMatching(
                    'posts',
                    'comments@post_id',
                    { page: 1, perPage: 25 },
                    { field: 'id', order: 'DESC' },
                    {}
                );

                // Update the main react-admin form (in this case, the comments creation form)
                change(REDUX_FORM_NAME, 'post_id', data.id);
                this.setState({ showDialog: false });
            })
            .catch(error => {
                showNotification(error.message, 'error');
            })
            .finally(() => {
                // Dispatch an action letting react-admin know a API call has ended
                fetchEnd();
            });
    };

    render() {
        const { showDialog } = this.state;
        const { isSubmitting } = this.props;

        return (
            <Fragment>
                <Button onClick={this.handleClick} label="ra.action.create">
                    <IconContentAdd />
                </Button>
                <Dialog
                    fullWidth
                    open={showDialog}
                    onClose={this.handleCloseClick}
                    aria-label="Create post"
                >
                    <DialogTitle>Create post</DialogTitle>
                    <DialogContent>
                        <SimpleForm
                            // We override the redux-form name to avoid collision with the react-admin main form
                            form="post-quick-create"
                            resource="posts"
                            // We override the redux-form onSubmit prop to handle the submission ourselves
                            onSubmit={this.handleSubmit}
                            // We want no toolbar at all as we have our modal actions
                            toolbar={null}
                        >
                            <TextInput source="title" validate={required()} />
                            <LongTextInput
                                source="teaser"
                                validate={required()}
                            />
                        </SimpleForm>
                    </DialogContent>
                    <DialogActions>
                        <SaveButton
                            saving={isSubmitting}
                            onClick={this.handleSaveClick}
                        />
                        <Button
                            label="ra.action.cancel"
                            onClick={this.handleCloseClick}
                        >
                            <IconCancel />
                        </Button>
                    </DialogActions>
                </Dialog>
            </Fragment>
        );
    }
}

const mapStateToProps = state => ({
    isSubmitting: isSubmitting('post-quick-create')(state)
});

const mapDispatchToProps = {
    change,
    crudGetMatching,
    fetchEnd,
    fetchStart,
    showNotification,
    submit
};

export default connect(mapStateToProps, mapDispatchToProps)(
    PostQuickCreateButton
);
Sparky answered 14/9, 2018 at 8:7 Comment(7)
having a dropdown (select or autocomplete) input in a modal renders the suggestions popup behind the modal and the user cannot see them.Fino
Use the mui styles to set the zindex correctly on the autocomplete/selectSparky
Hi @GildasGarcia, does this sample still work with react-admin version 3.x? I tried it with react-admin 3.2.3 but got error "TypeError: f.pauseValidation is not a function"Cabdriver
No it will not as we switched from redux-form to final-form. I will rewrite the tutorials ASAPSparky
@GildasGarcia Could you please provide the links when the updated tutorials are done? Perhaps you could provide a quick code sample for us to use in the mean time? :)Heracles
in case it helps someone, seems Gildas has kindly updated his tutorial for this (for react-admin v3 using react-final-form) - marmelab.com/blog/2020/04/27/…Featherweight
This tutorial is for custom create component. Is there an example for custom Edit component as well?Tullius

© 2022 - 2024 — McMap. All rights reserved.