how can I show customized error messaged from server side validation in React Admin package?

后端 未结 4 1422
栀梦
栀梦 2020-12-16 18:22

Is there any way to perform server side form validation using https://github.com/marmelab/react-admin package?

Here\'s the code for AdminCreate Component. It sends c

4条回答
  •  遥遥无期
    2020-12-16 18:57

    In addition to Christiaan Westerbeek's answer. I just recreating a SimpleForm component with some of Christian's hints. In begining i tried to extend SimpleForm with needed server-side validation functionality, but there were some issues (such as not binded context to its handleSubmitWithRedirect method), so i just created my CustomForm to use it in every place i need.

    import React, { Children, Component } from 'react';
    import PropTypes from 'prop-types';
    import { reduxForm, SubmissionError } from 'redux-form';
    import { connect } from 'react-redux';
    import compose from 'recompose/compose';
    import { withStyles } from '@material-ui/core/styles';
    import classnames from 'classnames';
    import { getDefaultValues, translate } from 'ra-core';
    import FormInput from 'ra-ui-materialui/lib/form/FormInput';
    import Toolbar  from 'ra-ui-materialui/lib/form/Toolbar';
    import {CREATE, UPDATE} from 'react-admin';
    import { showNotification as showNotificationAction } from 'react-admin';
    import { push as pushAction } from 'react-router-redux';
    
    import dataProvider from "../../providers/dataProvider";
    
    const styles = theme => ({
        form: {
            [theme.breakpoints.up('sm')]: {
                padding: '0 1em 1em 1em',
            },
            [theme.breakpoints.down('xs')]: {
                padding: '0 1em 5em 1em',
            },
        },
    });
    
    const sanitizeRestProps = ({
       anyTouched,
       array,
       asyncValidate,
       asyncValidating,
       autofill,
       blur,
       change,
       clearAsyncError,
       clearFields,
       clearSubmit,
       clearSubmitErrors,
       destroy,
       dirty,
       dispatch,
       form,
       handleSubmit,
       initialize,
       initialized,
       initialValues,
       pristine,
       pure,
       redirect,
       reset,
       resetSection,
       save,
       submit,
       submitFailed,
       submitSucceeded,
       submitting,
       touch,
       translate,
       triggerSubmit,
       untouch,
       valid,
       validate,
       ...props
    }) => props;
    
    /*
     * Zend validation adapted catch(e) method.
     * Formatted as
     * e = {
     *    field_name: { errorType: 'messageText' }
     * }
     */
    const submit = (data, resource) => {
        let actionType = data.id ? UPDATE : CREATE;
    
        return dataProvider(actionType, resource, {data: {...data}}).catch(e => {
            let errorObject = {};
    
            for (let fieldName in e) {
                let fieldErrors = e[fieldName];
    
                errorObject[fieldName] = Object.values(fieldErrors).map(value => `${value}\n`);
            }
    
            throw new SubmissionError(errorObject);
        });
    };
    
    export class CustomForm extends Component {
        handleSubmitWithRedirect(redirect = this.props.redirect) {
            return this.props.handleSubmit(data => {
                return submit(data, this.props.resource).then((result) => {
                    let path;
    
                    switch (redirect) {
                        case 'create':
                            path = `/${this.props.resource}/create`;
                            break;
                        case 'edit':
                            path = `/${this.props.resource}/${result.data.id}`;
                            break;
                        case 'show':
                            path = `/${this.props.resource}/${result.data.id}/show`;
                            break;
                        default:
                            path = `/${this.props.resource}`;
                    }
    
                    this.props.dispatch(this.props.showNotification(`${this.props.resource} saved`));
    
                    return this.props.dispatch(this.props.push(path));
                });
            });
        }
    
        render() {
            const {
                basePath,
                children,
                classes = {},
                className,
                invalid,
                pristine,
                push,
                record,
                resource,
                showNotification,
                submitOnEnter,
                toolbar,
                version,
                ...rest
            } = this.props;
    
            return (
                
    {Children.map(children, input => { return ( ); })}
    {toolbar && React.cloneElement(toolbar, { handleSubmitWithRedirect: this.handleSubmitWithRedirect.bind(this), invalid, pristine, submitOnEnter, })}
    ); } } CustomForm.propTypes = { basePath: PropTypes.string, children: PropTypes.node, classes: PropTypes.object, className: PropTypes.string, defaultValue: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), handleSubmit: PropTypes.func, // passed by redux-form invalid: PropTypes.bool, pristine: PropTypes.bool, push: PropTypes.func, record: PropTypes.object, resource: PropTypes.string, redirect: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), save: PropTypes.func, // the handler defined in the parent, which triggers the REST submission showNotification: PropTypes.func, submitOnEnter: PropTypes.bool, toolbar: PropTypes.element, validate: PropTypes.func, version: PropTypes.number, }; CustomForm.defaultProps = { submitOnEnter: true, toolbar: , }; const enhance = compose( connect((state, props) => ({ initialValues: getDefaultValues(state, props), push: pushAction, showNotification: showNotificationAction, })), translate, // Must be before reduxForm so that it can be used in validation reduxForm({ form: 'record-form', destroyOnUnmount: false, enableReinitialize: true, }), withStyles(styles) ); export default enhance(CustomForm);

    For better understanding of my catch callback: In my data provider i do something like this

    ...
        if (response.status !== 200) {
             return Promise.reject(response);
        }
    
        return response.json().then((json => {
    
            if (json.state === 0) {
                return Promise.reject(json.errors);
            }
    
            switch(type) {
            ...
            }
        ...
        }
    ...
    

提交回复
热议问题