1 | # rc-form
|
2 |
|
3 | React High Order Form Component.
|
4 |
|
5 | [![NPM version][npm-image]][npm-url]
|
6 | [![build status][travis-image]][travis-url]
|
7 | [![Test coverage][coveralls-image]][coveralls-url]
|
8 | [![gemnasium deps][gemnasium-image]][gemnasium-url]
|
9 | [![node version][node-image]][node-url]
|
10 | [![npm download][download-image]][download-url]
|
11 |
|
12 | [npm-image]: http://img.shields.io/npm/v/rc-form.svg?style=flat-square
|
13 | [npm-url]: http://npmjs.org/package/rc-form
|
14 | [travis-image]: https://img.shields.io/travis/react-component/form.svg?style=flat-square
|
15 | [travis-url]: https://travis-ci.org/react-component/form
|
16 | [coveralls-image]: https://img.shields.io/coveralls/react-component/form.svg?style=flat-square
|
17 | [coveralls-url]: https://coveralls.io/r/react-component/form?branch=master
|
18 | [gemnasium-image]: http://img.shields.io/gemnasium/react-component/form.svg?style=flat-square
|
19 | [gemnasium-url]: https://gemnasium.com/react-component/form
|
20 | [node-image]: https://img.shields.io/badge/node.js-%3E=_0.10-green.svg?style=flat-square
|
21 | [node-url]: http://nodejs.org/download/
|
22 | [download-image]: https://img.shields.io/npm/dm/rc-form.svg?style=flat-square
|
23 | [download-url]: https://npmjs.org/package/rc-form
|
24 |
|
25 | ## Development
|
26 |
|
27 | ```
|
28 | npm install
|
29 | npm start
|
30 | open http://localhost:8000/examples/
|
31 | ```
|
32 |
|
33 | ## Feature
|
34 |
|
35 | * Support react.js and even react-native
|
36 | * Validate fields with [async-validator](https://github.com/yiminghe/async-validator/)
|
37 |
|
38 | ## Install
|
39 |
|
40 | [![rc-form](https://nodei.co/npm/rc-form.png)](https://npmjs.org/package/rc-form)
|
41 |
|
42 | ## Usage
|
43 |
|
44 | ```js
|
45 | import { createForm, formShape } from 'rc-form';
|
46 |
|
47 | class Form extends React.Component {
|
48 | static propTypes = {
|
49 | form: formShape,
|
50 | };
|
51 |
|
52 | submit = () => {
|
53 | this.props.form.validateFields((error, value) => {
|
54 | console.log(error, value);
|
55 | });
|
56 | }
|
57 |
|
58 | render() {
|
59 | let errors;
|
60 | const { getFieldProps, getFieldError } = this.props.form;
|
61 | return (
|
62 | <div>
|
63 | <input {...getFieldProps('normal')}/>
|
64 | <input {...getFieldProps('required', {
|
65 | onChange(){}, // have to write original onChange here if you need
|
66 | rules: [{required: true}],
|
67 | })}/>
|
68 | {(errors = getFieldError('required')) ? errors.join(',') : null}
|
69 | <button onClick={this.submit}>submit</button>
|
70 | </div>
|
71 | );
|
72 | }
|
73 | }
|
74 |
|
75 | export createForm()(Form);
|
76 | ```
|
77 |
|
78 | ### use width react native
|
79 |
|
80 | Expo preview
|
81 |
|
82 | ![avatar](./examples/react-native/expo.jpg)
|
83 |
|
84 | [View the source code](./examples/react-native/App.js)
|
85 |
|
86 | Or a quicker version:
|
87 |
|
88 | ```js
|
89 | import { createForm } from 'rc-form';
|
90 |
|
91 | class Form extends React.Component {
|
92 | componentWillMount() {
|
93 | this.requiredDecorator = this.props.form.getFieldDecorator('required', {
|
94 | rules: [{required: true}],
|
95 | });
|
96 | }
|
97 |
|
98 | submit = () => {
|
99 | this.props.form.validateFields((error, value) => {
|
100 | console.log(error, value);
|
101 | });
|
102 | }
|
103 |
|
104 | render() {
|
105 | let errors;
|
106 | const { getFieldError } = this.props.form;
|
107 | return (
|
108 | <div>
|
109 | {this.requiredDecorator(
|
110 | <input
|
111 | onChange={
|
112 | // can still write your own onChange
|
113 | }
|
114 | />
|
115 | )}
|
116 | {(errors = getFieldError('required')) ? errors.join(',') : null}
|
117 | <button onClick={this.submit}>submit</button>
|
118 | </div>
|
119 | );
|
120 | }
|
121 | }
|
122 |
|
123 | export createForm()(Form);
|
124 | ```
|
125 |
|
126 | ## createForm(option: Object) => (WrappedComponent: React.Component) => React.Component
|
127 |
|
128 | | Option | Description | Type | Default |
|
129 | |-----------|------------------------------------------|------------|---------|
|
130 | | option.validateMessages | Preseted messages of [async-validator](https://github.com/yiminghe/async-validator) | Object | {} |
|
131 | | option.onFieldsChange | Called when field changed, you can dispatch fields to redux store. | (props, changed, all): void | NOOP |
|
132 | | option.onValuesChange | Called when value changed. | (props, changed, all): void | NOOP |
|
133 | | option.mapProps | Get new props transfered to WrappedComponent. | (props): Object | props => props |
|
134 | | option.mapPropsToFields | Convert value from props to fields. Used for read fields from redux store. | (props): Object | NOOP |
|
135 | | option.fieldNameProp | Where to store the `name` argument of `getFieldProps`. | String | - |
|
136 | | option.fieldMetaProp | Where to store the meta data of `getFieldProps`. | String | - |
|
137 | | option.fieldDataProp | Where to store the field data | String | - |
|
138 | | option.withRef(deprecated) | Maintain an ref for wrapped component instance, use `refs.wrappedComponent` to access. | boolean | false |
|
139 |
|
140 | ### Note: use wrappedComponentRef instead of withRef after rc-form@1.4.0
|
141 |
|
142 | ```jsx
|
143 | class Form extends React.Component { ... }
|
144 |
|
145 | // deprecated
|
146 | const EnhancedForm = createForm({ withRef: true })(Form);
|
147 | <EnhancedForm ref="form" />
|
148 | this.refs.form.refs.wrappedComponent // => The instance of Form
|
149 |
|
150 | // Recommended
|
151 | const EnhancedForm = createForm()(Form);
|
152 | <EnhancedForm wrappedComponentRef={(inst) => this.formRef = inst} />
|
153 | this.formRef // => The instance of Form
|
154 | ```
|
155 |
|
156 | ## (WrappedComponent: React.Component) => React.Component
|
157 |
|
158 | The returned function of createForm(). It will pass an object as prop `form` with the following members to WrappedComponent:
|
159 |
|
160 | ### getFieldProps(name, option): Object { [valuePropName], [trigger], [validateTrigger] }
|
161 |
|
162 | Will create props which can be set on a input/InputComponent which support value and onChange interface.
|
163 |
|
164 | After set, this will create a binding with this input.
|
165 |
|
166 | ```jsx
|
167 | <form>
|
168 | <input {...getFieldProps('name', { ...options })} />
|
169 | </form>
|
170 | ```
|
171 |
|
172 | #### name: String
|
173 |
|
174 | This input's unique name.
|
175 |
|
176 | #### option: Object
|
177 |
|
178 | | Option | Description | Type | Default |
|
179 | |-----------|------------------------------------------|------------|---------|
|
180 | | option.valuePropName | Prop name of component's value field, eg: checkbox should be set to `checked` ... | String | 'value' |
|
181 | | option.getValueProps | Get the component props according to field value. | (value): Object | (value) => ({ value }) |
|
182 | | option.getValueFromEvent | Specify how to get value from event. | (e): any | See below |
|
183 | | option.initialValue | Initial value of current component. | any | - |
|
184 | | option.normalize | Return normalized value. | (value, prev, all): Object | - |
|
185 | | option.trigger | Event which is listened to collect form data. | String | 'onChange' |
|
186 | | option.validateTrigger | Event which is listened to validate. Set to falsy to only validate when call props.validateFields. | String|String[] | 'onChange' |
|
187 | | option.rules | Validator rules. see: [async-validator](https://github.com/yiminghe/async-validator) | Object[] | - |
|
188 | | option.validateFirst | Whether stop validate on first rule of error for this field. | boolean | false |
|
189 | | option.validate | | Object[] | - |
|
190 | | option.validate[n].trigger | Event which is listened to validate. Set to falsy to only validate when call props.validateFields. | String|String[] | 'onChange' |
|
191 | | option.validate[n].rules | Validator rules. see: [async-validator](https://github.com/yiminghe/async-validator) | Object[] | - |
|
192 | | option.hidden | Ignore current field while validating or gettting fields | boolean | false |
|
193 |
|
194 | ##### Default value of `getValueFromEvent`
|
195 |
|
196 | ```js
|
197 | function defaultGetValueFromEvent(e) {
|
198 | if (!e || !e.target) {
|
199 | return e;
|
200 | }
|
201 | const { target } = e;
|
202 | return target.type === 'checkbox' ? target.checked : target.value;
|
203 | }
|
204 | ```
|
205 |
|
206 | ##### Tips
|
207 |
|
208 | ```js
|
209 | {
|
210 | validateTrigger: 'onBlur',
|
211 | rules: [{required: true}],
|
212 | }
|
213 | // is the shorthand of
|
214 | {
|
215 | validate: [{
|
216 | trigger: 'onBlur',
|
217 | rules: [required: true],
|
218 | }],
|
219 | }
|
220 | ```
|
221 |
|
222 | ### getFieldDecorator(name:String, option: Object) => (React.Node) => React.Node
|
223 |
|
224 | Similar to `getFieldProps`, but add some helper warnings and you can write onXX directly inside React.Node props:
|
225 |
|
226 | ```jsx
|
227 | <form>
|
228 | {getFieldDecorator('name', otherOptions)(<input />)}
|
229 | </form>
|
230 | ```
|
231 |
|
232 | ### getFieldsValue([fieldNames: String[]])
|
233 |
|
234 | Get fields value by fieldNames.
|
235 |
|
236 | ### getFieldValue(fieldName: String)
|
237 |
|
238 | Get field value by fieldName.
|
239 |
|
240 | ### getFieldInstance(fieldName: String)
|
241 |
|
242 | Get field react public instance by fieldName.
|
243 |
|
244 | ### setFieldsValue(obj: Object)
|
245 |
|
246 | Set fields value by kv object.
|
247 |
|
248 | ### setFieldsInitialValue(obj: Object)
|
249 |
|
250 | Set fields initialValue by kv object. use for reset and initial display/value.
|
251 |
|
252 | ### setFields(obj: Object)
|
253 |
|
254 | Set fields by kv object. each field can contain errors and value member.
|
255 |
|
256 | ### validateFields([fieldNames: String[]], [options: Object], callback: (errors, values) => void)
|
257 |
|
258 | Validate and get fields value by fieldNames.
|
259 |
|
260 | options is the same as validate method of [async-validator](https://github.com/yiminghe/async-validator).
|
261 | And add `force` and `scroll`. `scroll` is the same as [dom-scroll-into-view's function parameter `config`](https://github.com/yiminghe/dom-scroll-into-view#function-parameter).
|
262 |
|
263 | #### options.force: Boolean
|
264 |
|
265 | Defaults to false. Whether to validate fields which have been validated(caused by validateTrigger).
|
266 |
|
267 | ### getFieldsError(names): Object{ [name]: String[] }
|
268 |
|
269 | Get inputs' validate errors.
|
270 |
|
271 | ### getFieldError(name): String[]
|
272 |
|
273 | Get input's validate errors.
|
274 |
|
275 | ### isFieldValidating(name: String): Bool
|
276 |
|
277 | Whether this input is validating.
|
278 |
|
279 | ### isFieldsValidating(names: String[]): Bool
|
280 |
|
281 | Whether one of the inputs is validating.
|
282 |
|
283 | ### isFieldTouched(name: String): Bool
|
284 |
|
285 | Whether this input's value had been changed by user.
|
286 |
|
287 | ### isFieldsTouched(names: String[]): Bool
|
288 |
|
289 | Whether one of the inputs' values had been changed by user.
|
290 |
|
291 | ### resetFields([names: String[]])
|
292 |
|
293 | Reset specified inputs. Defaults to all.
|
294 |
|
295 | ### isSubmitting(): Bool (Deprecated)
|
296 |
|
297 | Whether the form is submitting.
|
298 |
|
299 | ### submit(callback: Function) (Deprecated)
|
300 |
|
301 | Cause isSubmitting to return true, after callback called, isSubmitting return false.
|
302 |
|
303 |
|
304 | ## rc-form/lib/createDOMForm(option): Function
|
305 |
|
306 | createDOMForm enhancement, support props.form.validateFieldsAndScroll
|
307 |
|
308 | ### validateFieldsAndScroll([fieldNames: String[]], [options: Object], callback: (errors, values) => void)
|
309 |
|
310 | props.form.validateFields enhancement, support scroll to the first invalid form field
|
311 |
|
312 | #### options.container: HTMLElement
|
313 |
|
314 | Defaults to first scrollable container of form field(until document).
|
315 |
|
316 |
|
317 | ## Notes
|
318 |
|
319 | - Do not use stateless function component inside Form component: https://github.com/facebook/react/pull/6534
|
320 |
|
321 | - you can not set same prop name as the value of validateTrigger/trigger for getFieldProps
|
322 |
|
323 | ```js
|
324 | <input {...getFieldProps('change',{
|
325 | onChange: this.iWantToKnow // you must set onChange here or use getFieldDecorator to write inside <input>
|
326 | })}>
|
327 | ```
|
328 |
|
329 | - you can not use ref prop for getFieldProps
|
330 |
|
331 | ```js
|
332 | <input {...getFieldProps('ref')} />
|
333 |
|
334 | this.props.form.getFieldInstance('ref') // use this to get ref
|
335 | ```
|
336 |
|
337 | or
|
338 |
|
339 | ```js
|
340 | <input {...getFieldProps('ref',{
|
341 | ref: this.saveRef // use function here or use getFieldDecorator to write inside <input> (only allow function)
|
342 | })} />
|
343 | ```
|
344 |
|
345 | ## Test Case
|
346 |
|
347 | ```
|
348 | npm test
|
349 | npm run chrome-test
|
350 | ```
|
351 |
|
352 | ## Coverage
|
353 |
|
354 | ```
|
355 | npm run coverage
|
356 | ```
|
357 |
|
358 | open coverage/ dir
|
359 |
|
360 | ## License
|
361 |
|
362 | rc-form is released under the MIT license.
|