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 create request to api. Api returns validation error with status code 422 or status code 200 if everything is ok.
export class AdminCreate extends Component { render() { return <Create {...this.props}> <SimpleForm> <TextInput source="name" type="text" /> <TextInput source="email" type="email"/> <TextInput source="password" type="password"/> <TextInput source="password_confirmation" type="password"/> <TextInput source="phone" type="tel"/> </SimpleForm> </Create>; } }
So the question is, how can I show errors for each field separately from error object sent from server? Here is the example of error object:
{ errors: {name: "The name is required", email: "The email is required"}, message: "invalid data" }
Thank you in advance!
class SimpleForm extends Component { handleSubmitWithRedirect = (redirect = this.props.redirect) => this.props.handleSubmit(data => { dataProvider(CREATE, 'admins', { data: { ...data } }).catch(e => { throw new SubmissionError(e.body.errors) }).then(/* Here must be redirection logic i think */); }); render() { const { basePath, children, classes = {}, className, invalid, pristine, record, resource, submitOnEnter, toolbar, version, ...rest } = this.props; return ( <form className={classnames('simple-form', className)} {...sanitizeRestProps(rest)} > <div className={classes.form} key={version}> {Children.map(children, input => ( <FormInput basePath={basePath} input={input} record={record} resource={resource} /> ))} </div> {toolbar && React.cloneElement(toolbar, { handleSubmitWithRedirect: this.handleSubmitWithRedirect, invalid, pristine, submitOnEnter, })} </form> ); } }
Now i have following code, and it’s showing validation errors. But the problem is, i can’t perform redirection after success. Any thoughts?
Advertisement
Answer
If you’re using SimpleForm, you can use asyncValidate
together with asyncBlurFields
as suggested in a comment in issue 97. I didn’t use SimpleForm, so this is all I can tell you about that.
I’ve used a simple form
. And you can use server-side validation there as well. Here’s how I’ve done it. A complete and working example.
import React from 'react'; import PropTypes from 'prop-types'; import { Field, propTypes, reduxForm, SubmissionError } from 'redux-form'; import { connect } from 'react-redux'; import compose from 'recompose/compose'; import { CardActions } from 'material-ui/Card'; import Button from 'material-ui/Button'; import TextField from 'material-ui/TextField'; import { CircularProgress } from 'material-ui/Progress'; import { CREATE, translate } from 'ra-core'; import { dataProvider } from '../../providers'; // <-- Make sure to import yours! const renderInput = ({ meta: { touched, error } = {}, input: { ...inputProps }, ...props }) => ( <TextField error={!!(touched && error)} helperText={touched && error} {...inputProps} {...props} fullWidth /> ); /** * Inspired by * - https://redux-form.com/6.4.3/examples/submitvalidation/ * - https://marmelab.com/react-admin/Actions.html#using-a-data-provider-instead-of-fetch */ const submit = data => dataProvider(CREATE, 'things', { data: { ...data } }).catch(e => { const payLoadKeys = Object.keys(data); const errorKey = payLoadKeys.length === 1 ? payLoadKeys[0] : '_error'; // Here I set the error either on the key by the name of the field // if there was just 1 field in the payload. // The `Field` with the same `name` in the `form` wil have // the `helperText` shown. // When multiple fields where present in the payload, the error message is set on the _error key, making the general error visible. const errorObject = { [errorKey]: e.message, }; throw new SubmissionError(errorObject); }); const MyForm = ({ isLoading, handleSubmit, error, translate }) => ( <form onSubmit={handleSubmit(submit)}> <div> <div> <Field name="email" component={renderInput} label="Email" disabled={isLoading} /> </div> </div> <CardActions> <Button variant="raised" type="submit" color="primary" disabled={isLoading} > {isLoading && <CircularProgress size={25} thickness={2} />} Signin </Button> {error && <strong>General error: {translate(error)}</strong>} </CardActions> </form> ); MyForm.propTypes = { ...propTypes, classes: PropTypes.object, redirectTo: PropTypes.string, }; const mapStateToProps = state => ({ isLoading: state.admin.loading > 0 }); const enhance = compose( translate, connect(mapStateToProps), reduxForm({ form: 'aFormName', validate: (values, props) => { const errors = {}; const { translate } = props; if (!values.email) errors.email = translate('ra.validation.required'); return errors; }, }) ); export default enhance(MyForm);
If the code needs further explanation, drop a comment below and I’ll try to elaborate.
I hoped to be able to do the action of the REST-request by dispatching an action with onSuccess and onFailure side effects as described here, but I couldn’t get that to work together with SubmissionError
.