diff --git a/components/form/FormItem.tsx b/components/form/FormItem.tsx index 1f44d856bb..cb3cebaa0c 100644 --- a/components/form/FormItem.tsx +++ b/components/form/FormItem.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; import classNames from 'classnames'; +import intersperse from 'intersperse'; import Animate from 'rc-animate'; import Row from '../grid/row'; import Col, { ColProps } from '../grid/col'; @@ -65,15 +66,20 @@ export default class FormItem extends React.Component { ); } - getHelpMsg() { - const props = this.props; - const onlyControl = this.getOnlyControl(); - if (props.help === undefined && onlyControl) { + getHelpMessage() { + const { help } = this.props; + if (help === undefined && this.getOnlyControl()) { const errors = this.getField().errors; - return errors ? errors.map((e: any) => e.message).join(', ') : ''; + if (errors) { + return intersperse(errors.map((e: any, index: number) => ( + React.isValidElement(e.message) + ? React.cloneElement(e.message, { key: index }) + : e.message + )), ' '); + } + return ''; } - - return props.help; + return help; } getControls(children: React.ReactNode, recursively: boolean) { @@ -129,7 +135,7 @@ export default class FormItem extends React.Component { renderHelp() { const prefixCls = this.props.prefixCls; - const help = this.getHelpMsg(); + const help = this.getHelpMessage(); const children = help ? (
{help} @@ -306,7 +312,7 @@ export default class FormItem extends React.Component { const style = props.style; const itemClassName = { [`${prefixCls}-item`]: true, - [`${prefixCls}-item-with-help`]: !!this.getHelpMsg() || this.state.helpShow, + [`${prefixCls}-item-with-help`]: !!this.getHelpMessage() || this.state.helpShow, [`${prefixCls}-item-no-colon`]: !props.colon, [`${props.className}`]: !!props.className, }; diff --git a/components/form/__tests__/__snapshots__/message.test.js.snap b/components/form/__tests__/__snapshots__/message.test.js.snap new file mode 100644 index 0000000000..5c892b01b2 --- /dev/null +++ b/components/form/__tests__/__snapshots__/message.test.js.snap @@ -0,0 +1,100 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Form should display custom message 1`] = ` +
+
+
+ +
+
+
+ + + +
+ + Account does not exist, + + Forgot account? + + +
+
+
+
+
+`; + +exports[`Form should display two message 1`] = ` +
+
+
+ +
+
+
+ + + +
+ Error message 1 Error message 2 +
+
+
+
+
+`; diff --git a/components/form/__tests__/message.test.js b/components/form/__tests__/message.test.js new file mode 100644 index 0000000000..8dc86ea3a5 --- /dev/null +++ b/components/form/__tests__/message.test.js @@ -0,0 +1,56 @@ +import React from 'react'; +import { mount } from 'enzyme'; +import Form from '..'; + +describe('Form', () => { + it('should display two message', () => { + const rules = [{ + pattern: /^\w+$/, + message: 'Error message 1', + }, { + pattern: /^\w+$/, + message: 'Error message 2', + }]; + let myForm; + const Form1 = Form.create()(({ form }) => { + myForm = form; + return ( +
+ + {form.getFieldDecorator('account', { initialValue: '+=-/', rules })()} + +
+ ); + }); + + const wrapper = mount(); + myForm.validateFields(); + + wrapper.update(); + expect(wrapper.render()).toMatchSnapshot(); + }); + + it('should display custom message', () => { + const rules = [{ + pattern: /^$/, + message: (Account does not exist, Forgot account?), + }]; + let myForm; + const Form1 = Form.create()(({ form }) => { + myForm = form; + return ( +
+ + {form.getFieldDecorator('account', { initialValue: 'antd', rules })()} + +
+ ); + }); + + const wrapper = mount(); + myForm.validateFields(); + + wrapper.update(); + expect(wrapper.render()).toMatchSnapshot(); + }); +}); diff --git a/components/form/index.en-US.md b/components/form/index.en-US.md index 019c82bebd..2f74c52a15 100644 --- a/components/form/index.en-US.md +++ b/components/form/index.en-US.md @@ -147,7 +147,7 @@ Note: | enum | validate a value from a list of possible values | string | - | | len | validate an exact length of a field | number | - | | max | validate a max length of a field | number | - | -| message | validation error message | string | - | +| message | validation error message | string\|ReactNode | - | | min | validate a min length of a field | number | - | | pattern | validate from a regular expression | RegExp | - | | required | indicates whether field is required | boolean | `false` | diff --git a/components/form/index.zh-CN.md b/components/form/index.zh-CN.md index 8361351c65..b3acf7301d 100644 --- a/components/form/index.zh-CN.md +++ b/components/form/index.zh-CN.md @@ -148,7 +148,7 @@ CustomizedForm = Form.create({})(CustomizedForm); | enum | 枚举类型 | string | - | | len | 字段长度 | number | - | | max | 最大长度 | number | - | -| message | 校验文案 | string | - | +| message | 校验文案 | string\|ReactNode | - | | min | 最小长度 | number | - | | pattern | 正则表达式校验 | RegExp | - | | required | 是否必选 | boolean | `false` | diff --git a/package.json b/package.json index 3e8e2a6982..822bab91c1 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "css-animation": "^1.2.5", "dom-closest": "^0.2.0", "enquire.js": "^2.1.1", + "intersperse": "^1.0.0", "lodash": "^4.17.5", "moment": "^2.19.3", "omit.js": "^1.0.0", diff --git a/typings/custom-typings.d.ts b/typings/custom-typings.d.ts index deed7d0bd9..a625a853ec 100644 --- a/typings/custom-typings.d.ts +++ b/typings/custom-typings.d.ts @@ -97,3 +97,5 @@ declare module "prop-types" declare module "lodash/debounce" declare module "lodash/uniqBy" + +declare module 'intersperse'; \ No newline at end of file