Javascript 如何在React Admin包中显示来自服务器端验证的自定义错误消息?
是否有任何方法可以使用包执行服务器端表单验证 下面是AdminCreate组件的代码。它向api发送创建请求。如果一切正常,Api返回状态代码为422或状态代码为200的验证错误Javascript 如何在React Admin包中显示来自服务器端验证的自定义错误消息?,javascript,reactjs,react-admin,Javascript,Reactjs,React Admin,是否有任何方法可以使用包执行服务器端表单验证 下面是AdminCreate组件的代码。它向api发送创建请求。如果一切正常,Api返回状态代码为422或状态代码为200的验证错误 export class AdminCreate extends Component { render() { return <Create {...this.props}> <SimpleForm> <TextInput sourc
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>;
}
}
提前谢谢你
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>
);
}
}
类SimpleForm扩展组件{
handleSubmitWithRedirect=(redirect=this.props.redirect)=>
this.props.handleSubmit(数据=>{
dataProvider(创建'admins',{data:{…data}}).catch(e=>{
抛出新提交错误(例如body.errors)
}).然后(/*我想这里一定是重定向逻辑*/);
});
render(){
常数{
基本路径,
儿童
类={},
类名,
无效的
崭新的
记录,
资源,,
次中心,
工具栏,
版本
休息
}=这是道具;
返回(
{Children.map(Children,input=>(
))}
{工具栏&&
React.cloneElement(工具栏{
handleSubmitWithRedirect:this.handleSubmitWithRedirect,
无效的
崭新的
次中心,
})}
);
}
}
现在我有了下面的代码,它显示了验证错误。但问题是,成功后我无法执行重定向。有什么想法吗 如果正在使用,则可以按照中的建议将asyncValidate
与asyncBlurFields
一起使用。我没有使用SimpleForm,所以我只能告诉你这些
我使用了一个简单的表单
。您也可以在那里使用服务器端验证。我是这样做的。一个完整的工作示例
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);
从“React”导入React;
从“道具类型”导入道具类型;
从'redux form'导入{Field,propTypes,reduxForm,SubmissionError};
从'react redux'导入{connect};
从“重新组合/组合”导入组合;
从“物料界面/卡片”导入{CardActions};
从“物料界面/按钮”导入按钮;
从“物料界面/文本字段”导入文本字段;
从“物料界面/进度”导入{CircularProgress};
从“ra核心”导入{CREATE,translate};
从“../../providers”;/”导入{dataProvider}(
);
/**
*灵感来自
* - 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=数据=>
数据提供者(创建,'things',{data:{…data}}).catch(e=>{
const payLoadKeys=Object.keys(数据);
const errorKey=payLoadKeys.length==1?payLoadKeys[0]:“_error”;
//在这里,我通过字段名在键上设置错误
//如果有效载荷中只有一个字段。
//在'form'中具有相同'name'的'Field'将具有
//显示“helperText”。
//当有效负载中存在多个字段时,将在_error键上设置错误消息,使常规错误可见。
常量错误对象={
[errorKey]:电子邮件,
};
抛出新提交错误(errorObject);
});
const MyForm=({isLoading,handleSubmit,error,translate})=>(
{isLoading&&}
签名
{error&一般错误:{translate(error)}}
);
MyForm.propTypes={
…道具类型,
类:PropTypes.object,
重定向到:PropTypes.string,
};
const-mapStateToProps=state=>({isLoading:state.admin.loading>0});
常数增强=合成(
翻译,
连接(MapStateTops),
红肿({
表格:'A表格名称',
验证:(值、道具)=>{
常量错误={};
const{translate}=props;
如果(!values.email)
errors.email=translate('ra.validation.required');
返回错误;
},
})
);
导出默认增强(MyForm);
如果代码需要进一步解释,请在下面添加注释,我将尝试详细说明
我希望能够通过调度一个具有所描述的onSuccess和onFailure副作用的操作来执行REST请求的操作,但我无法将其与
SubmissionError
配合使用 除了Christiaan Westerbeek的回答之外。
我只是用Christian的一些提示重新创建了一个SimpleForm组件。
在开始时,我尝试使用所需的服务器端验证功能扩展SimpleForm,但存在一些问题(例如没有将上下文绑定到它的handleSubmitWithRedirect
方法),所以我只创建了我的CustomForm,以便在我需要的每个地方使用它
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 (
<form
// onSubmit={this.props.handleSubmit(submit)}
className={classnames('simple-form', className)}
{...sanitizeRestProps(rest)}
>
<div className={classes.form} key={version}>
{Children.map(children, input => {
return (
<FormInput
basePath={basePath}
input={input}
record={record}
resource={resource}
/>
);
})}
</div>
{toolbar &&
React.cloneElement(toolbar, {
handleSubmitWithRedirect: this.handleSubmitWithRedirect.bind(this),
invalid,
pristine,
submitOnEnter,
})}
</form>
);
}
}
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: <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);
这里是官方回购的另一个解决方案。 您需要在DataProvider中导入HttpError(消息、状态、正文)并抛出它。 然后在errorSaga中,解析body以重排表单结构。 就这样。
享受。为react admin 3.8.1找到了一个有效的解决方案,看起来效果不错 这是参考代码 示例: 首先,根据需要使助手发挥作用
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
const simpleMemoize = fn => {
let lastArg;
let lastResult;
return arg => {
if (arg !== lastArg) {
lastArg = arg;
lastResult = fn(arg);
}
return lastResult;
};
};
然后是实际的验证代码
const usernameAvailable = simpleMemoize(async value => {
if (!value) {
return "Required";
}
await sleep(400);
if (
~["john", "paul", "george", "ringo"].indexOf(value && value.toLowerCase())
) {
return "Username taken!";
}
});
最后将其连接到您的领域:
const validateUserName=[required(),maxLength(10),abbrevUnique]
const UserNameInput = (props) => {
return (
<TextInput
label="User Name"
source="username"
variant='outlined'
validate={validateAbbrev}
>
</TextInput>);
}
constusernameinput=(props)=>{
返回(
);
}
我也在寻找这样做的方法。当我找到它的时候,我会回来的。如果我能正确地看到这一点,我将不胜感激。您的解决方案是创建一个自定义的
,它直接使用数据提供程序捕获错误并显示它?I fo
const usernameAvailable = simpleMemoize(async value => {
if (!value) {
return "Required";
}
await sleep(400);
if (
~["john", "paul", "george", "ringo"].indexOf(value && value.toLowerCase())
) {
return "Username taken!";
}
});
const UserNameInput = (props) => {
return (
<TextInput
label="User Name"
source="username"
variant='outlined'
validate={validateAbbrev}
>
</TextInput>);
}