Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Admin - Create and edit in modal

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

like image 491
Nicolas Kern Avatar asked Jul 12 '18 13:07

Nicolas Kern


People also ask

How to edit index of a modal in react?

Normally with working with arrays in react and you want to operate on an entry, then you pass in a callback the index of the element you want to work with. Create a new onClick handler that sets the index you want to edit and toggles the modal open

How to efficiently create records using React modal?

– Efficiently create record using React modal. We’ll set up a basic project providing context for the modal dialog with components and sample data. Then, we’ll go through the code, using two types of resources (Users and Posts), showing how to add User resources on the fly while creating new Posts.

How to edit the index of a modal without animation?

Create a new onClick handler that sets the index you want to edit and toggles the modal open editByIndex(editIndex) { this.setState({ editIndex }); this.toggleModal("modalWithoutAnimation"); }

Is the form in edit or add Mode?

The form is in "add mode" when there is no user id parameter ( match.params.id ), otherwise it is in "edit mode".


1 Answers

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
);
like image 183
Gildas Garcia Avatar answered Sep 20 '22 06:09

Gildas Garcia