Skip to content

Commit e64a09c

Browse files
author
bietkul
committed
2 parents 5da9f6d + 1b82bdc commit e64a09c

File tree

4 files changed

+215
-28
lines changed

4 files changed

+215
-28
lines changed

README.md

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
[![Build Status](https://travis-ci.org/bietkul/react-reactive-form.svg?branch=master)](https://travis-ci.org/bietkul/react-reactive-form)
44
[![NPM Version](https://img.shields.io/npm/v/react-reactive-form.svg?style=flat)](https://www.npmjs.com/package/react-reactive-form)
5+
[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)
56

67
It's a library inspired by the [Angular's Reactive Forms](https://angular.io/guide/reactive-forms), which allows to create a tree of form control objects in the component class and bind them with native form control elements.
78

@@ -14,7 +15,8 @@ It's a library inspired by the [Angular's Reactive Forms](https://angular.io/gui
1415
* Provides a set of validators & also supports custom sync & async validators.
1516
* Better form management with `FormGroup` & `FormArray` apis.
1617
* Customizable update strategy for better performace with large forms.
17-
# Installation
18+
19+
# Installation
1820

1921
```sh
2022
npm install react-reactive-form --save
@@ -105,9 +107,9 @@ export default class Login extends Component {
105107
}
106108
```
107109

108-
## Add Dynamic Control
110+
## Add Controls Dynamically
109111

110-
You can also create dynamic controls without even initializing the group control object with the help of new react form components ( [FieldGroup](docs/api/FieldGroup.md), [FieldControl](docs/api/FieldControl.md), [FieldArray](docs/api/FieldArray.md)).
112+
You can also create controls without even initializing the group control object with the help of new react form components ( [FieldGroup](docs/api/FieldGroup.md), [FieldControl](docs/api/FieldControl.md), [FieldArray](docs/api/FieldArray.md)).
111113

112114
```js
113115
import React, { Component } from 'react'
@@ -169,7 +171,7 @@ export default class Login extends Component {
169171
}
170172
```
171173

172-
<b>So, it's not mandatory that you need to define your control separately but if you want better control then you should do that, if your controls are dynamic then you can also initalize the empty group control and add the controls later.
174+
<b>So, it's not mandatory that you need to define your control separately but if you want a better control over your form state then you should do that, if your controls are dynamic then you can also initalize the empty group control and add the controls later.
173175
See the example:</b>
174176

175177
```js
@@ -256,7 +258,67 @@ export default class Login extends Component {
256258
* [User Registeration Form With Nested Forms](https://codesandbox.io/s/p2rqmr8qk7)
257259
* [Form Array With Dynamic Controls](https://codesandbox.io/s/nw9wxw2nvl)
258260
* [Update On Submit](https://codesandbox.io/s/3qk1ly16j1)
259-
* [Multi-page Wizard Form](https://codesandbox.io/s/zk1m06r5y3)
261+
* [Multi-page Wizard Form](https://codesandbox.io/s/136340om74)
262+
263+
264+
# FAQ
265+
266+
### How is it different from other form libraries?
267+
268+
React has many libraries which works on the form logic, but here are some concerns with these:
269+
270+
#### Code Complexity
271+
If you’re using the redux-form then you should know the pain, for just a two field login form you’d to write the store logic.In RRF you can see that how simple is to deal with simple and complex forms.
272+
273+
`And one of the awesome thing is that you can just write your form controls logic anywhere in your application.`
274+
275+
#### Dependencies
276+
Many libraries come with dependencies for e.g redux is required for redux-form, So what If I’m using another state management or not event using any.
277+
According to Dan Abramov, form state is inherently ephemeral and local, so tracking it in Redux (or any kind of Flux library) is unnecessary.
278+
RRF comes with `zero` dependency, So it’s totally up to you that how you want to save your form state if needed.
279+
280+
#### Performance
281+
Now that’s a big problem with almost all libraries when you're dealing with large forms.
282+
283+
How RRF does solve performance issues ?
284+
- It uses subscription to update the components so rather updating all the fields on every input changes, it only update the particular field for which the state change takes place.
285+
- RRF has a nice option to define that when(blur, submit or change) to update your form's state by using the `updateOn` property.
286+
287+
#### Dynamic Changes
288+
With the help of subscribers it's pretty easy to listen for a particular state changes and modify the controls accordingly.
289+
290+
291+
### What are `value` and `status` changes subscribers?
292+
293+
RRF uses inbuilt `Subject`, A `Subject` is an object with the method next(v).To feed a new value to the Subject,RRF just calls the next(theValue), and it will be multicasted to the Observers registered to listen to the Subject.
294+
So basically it provides three subjects for each AbstractControl `valueChanges`, `statusChanges` and `stateChanges` and additional two subjects for FormControl ( `onValueChanges`, `onBlurChanges`)
295+
You can register an observer to a particular Subject to do some actions whenever some particular changes happen.
296+
297+
Example:
298+
299+
```ts
300+
componentDidMount() {
301+
this.myForm.get(“gender”).valueChanges.subscribe((value) => {
302+
// do something
303+
})
304+
}
305+
```
306+
Checkout the [Basic usage guide](docs) for more details.
307+
308+
### How the Field components work?
309+
310+
Field components are subscribed to the state changes of a particular control which means that it’ll re-render the component only when it’s state changes disregarding of other field changes.You can also implement your custom wrappers by using the stateChanges `Subject`.
311+
312+
### How updateOn feature works?
313+
314+
Its an another performance booster in RRF, it just holds the computation needed to be made after every keystroke or value changes until you want to execute.It has three options `change`(default), `blur` and `submit`, you can define all of them at both field and record level.
315+
316+
### Is this library compatible with React Native?
317+
318+
Yes, this library works with react-native also, currently it supports react-native `TextInput` and `Switch` component.
319+
320+
321+
260322

261323
Let's make React Reactive Forms better! If you're interested in helping, all contributions are welcome and appreciated.
262324

docs/GettingStarted.md

Lines changed: 129 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ The basic implementation of reactive forms is super easy but it may be helpful t
1010
### step 1: Create FormGroup or FormArray
1111
A form group is a collection object of form controls & form array is the collection array of form controls.
1212

13-
There are two ways to create these:
13+
There are three ways to create these:
1414

15-
#### With FormBuilder
15+
#### With FormBuilder ( Static Controls )
1616
The FormBuilder class helps reduce repetition and clutter by handling details of control creation for you.
1717
`FormBuilder.group` is a static method that creates a FormGroup. `FormBuilder.group` takes an object whose keys and values are
1818
`FormControl` names and their definitions. In this example, the username control is defined by its initial data value,
@@ -30,7 +30,7 @@ const loginForm = FormBuilder.group({
3030
});
3131
```
3232

33-
#### Without FormBuilder
33+
#### Without FormBuilder ( Static Controls )
3434

3535
```js
3636
import { FormGroup, FormControl } from "react-reactive-form";
@@ -41,79 +41,103 @@ const loginForm = new FormGroup({
4141
})
4242
```
4343

44+
#### Without initializing the controls ( Dynamic Controls )
45+
46+
You can also create controls without even initializing the group control object with the help of new react form components ( [FieldGroup](api/FieldGroup.md), [FieldControl](api/FieldControl.md), [FieldArray](api/FieldArray.md)).
47+
48+
For eg.
49+
50+
```ts
51+
<FieldGroup
52+
render={({ value }) => (
53+
<form>
54+
<FieldControl
55+
name="test"
56+
render={({ handler }) => <input {...handler()}/>}
57+
/>
58+
<pre>{value.toString()}</pre>
59+
</form>)}
60+
/>
61+
```
62+
The above example will create an instance of [FormGroup](FormGroup.md) class which has a control named `test`.
63+
64+
4465
### step2: Connect form with component
45-
[Field](api/Field.md) component subscribes a particular control & only update it when it’s or it’s parent’s state changes, which improves the performance by restricting the unnecessary re-rendering of other fields.
66+
This steps is not needed if you're using dynamic controls but if you want a better control over your form state then you should do that, if your controls are dynamic then you can also initalize the empty group control and add the controls later.
67+
Example:
4668

4769
```js
4870
import React, { Component } from 'react';
49-
import { FormBuilder, Validators, Field } from "react-reactive-form";
71+
import {
72+
FormBuilder,
73+
FieldGroup,
74+
FieldControl,
75+
Validators,
76+
} from "react-reactive-form";
5077

5178
export default class Login extends Component {
52-
constructor(props) {
53-
super(props);
54-
// Create the controls
55-
this.loginForm = FormBuilder.group({
79+
loginForm = FormBuilder.group({
5680
username: ["", Validators.required],
5781
password: ["", Validators.required],
5882
rememberMe: false
5983
});
6084
}
61-
handleReset=(e) => {
85+
handleReset=() => {
6286
this.loginForm.reset();
63-
e.preventDefault();
6487
}
6588
handleSubmit=(e) => {
66-
console.log("Form values", this.loginForm.value);
6789
e.preventDefault();
90+
console.log("Form values", this.loginForm.value);
6891
}
6992
render() {
7093
return (
71-
<Field
94+
<FieldGroup
7295
control={this.loginForm}
7396
render={({ get, invalid }) => (
7497
<form onSubmit={this.handleSubmit}>
75-
<Field
76-
control={get("username")}
98+
<FieldControl
99+
name="username"
77100
render={({ handler, touched, hasError }) => (
78101
<div>
79102
<input {...handler()}/>
80103
<span>
81-
{touched
104+
{touched
82105
&& hasError("required")
83106
&& "Username is required"}
84107
</span>
85108
</div>
86109
)}
87110
/>
88-
<Field
89-
control={get("password")}
111+
<FieldControl
112+
name="password"
90113
render={({ handler, touched, hasError }) => (
91114
<div>
92115
<input {...handler()}/>
93116
<span>
94-
{touched
117+
{touched
95118
&& hasError("required")
96119
&& "Password is required"}
97120
</span>
98121
</div>
99122
)}
100123
/>
101-
<Field
102-
control={get("rememberMe")}
124+
<FieldControl
125+
name="rememberMe"
103126
render={({handler}) => (
104127
<div>
105128
<input {...handler("checkbox")}/>
106129
</div>
107130
)}
108131
/>
109-
<button
132+
<button
133+
type="button"
110134
onClick={this.handleReset}
111135
>
112136
Reset
113137
</button>
114138
<button
115139
type="submit"
116-
disabled={invalid}
140+
disabled={invalid}
117141
>
118142
Submit
119143
</button>
@@ -124,3 +148,85 @@ export default class Login extends Component {
124148
}
125149
}
126150
```
151+
152+
## Common Operations
153+
154+
### Add Listeners
155+
156+
You can add subscriptions for listening the state changes in form.
157+
There are a total of five observables available currently:
158+
159+
#### valueChanges
160+
Emits an event every time when the control's value changes.
161+
#### stateChanges
162+
Emits an event every time when the control's state(value, touched, ...) changes.
163+
#### statusChanges
164+
Emits an event every time when the control's status(PENDING, INVALID, VALID, DISABLED) changes.
165+
#### onValueChanges
166+
Emits an event every time when the control's value is changed by onChange event i.e by user.
167+
#### onBlurChnages
168+
Emits an event every time when a blur event triggers on a control.
169+
170+
You can use these listeners to modify the form state dynamically based on the value of other controls.
171+
172+
Example:
173+
174+
#### Disable/Enable a control based on another control's value
175+
176+
```js
177+
class Form extends Component {
178+
myForm = {
179+
public: true,
180+
images: [[]]
181+
}
182+
componentDidMount() {
183+
this.myForm.get('public').valueChanges.subscribe((value) => {
184+
const imagesControl = this.myForm.get('images')
185+
if(value) {
186+
imagesControl.disable()
187+
} else {
188+
imagesControl.enable()
189+
}
190+
})
191+
}
192+
componentWillUnmount() {
193+
this.myForm.get('public').valueChanges.unsubscribe()
194+
}
195+
}
196+
```
197+
198+
#### Set the value of a control based on another control's value
199+
200+
The following example ensures that one of the control's value must be `true`.
201+
202+
```js
203+
class Form extends Component {
204+
myForm = {
205+
showMeMen: true,
206+
showMeWomen: true
207+
}
208+
componentDidMount() {
209+
const showMeMenControl = this.myForm.get('showMeMen').unsubscribe()
210+
const showMeWomenControl = this.myForm.get('showMeWomen')
211+
212+
showMeMenControl.valueChanges.subscribe((value) => {
213+
if(!value && !showMeWomenControl.value) {
214+
showMeWomenControl.setValue(true)
215+
}
216+
})
217+
218+
showMeWomenControl.valueChanges.subscribe((value) => {
219+
if(!value && !showMeMenControl.value) {
220+
showMeMenControl.setValue(true)
221+
}
222+
})
223+
224+
}
225+
226+
componentWillUnmount() {
227+
this.myForm.get('showMeMen').valueChanges.unsubscribe()
228+
this.myForm.get('showMeWomen').valueChanges.unsubscribe()
229+
}
230+
}
231+
```
232+

docs/api/FormControl.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,16 @@ onBlur: () => void;
116116
Function needs to be called whenever a blur event triggers.
117117
##
118118
```ts
119+
onValueChanges: Observable<any>;
120+
```
121+
Emits an event every time the value of the control changes, in the UI by onChange event.
122+
##
123+
```ts
124+
onBlurChanges: Observable<any>;
125+
```
126+
Emits an event every time whenever a blur event triggers.
127+
##
128+
```ts
119129
handler: (inputType?: InputType, value?: string) => Handler;
120130
```
121131
Returns the props required to bind a control to a native input element.

docs/api/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,15 @@
33
## [Field](Field.md)
44
A subscription based higher order component which connects a control with react component.
55

6+
## [FieldControl](FieldControl.md)
7+
A subscription based higher order component which connects an instance of [FormControl](FormControl.md) with react component.
8+
9+
## [FieldGroup](FieldGroup.md)
10+
A subscription based higher order component which connects an instance of [FormGroup](FormGroup.md) with react component.
11+
12+
## [FieldArray](FieldArray.md)
13+
A subscription based higher order component which connects an instance of [FormArray](FormArray.md) with react component.
14+
615
## [Abstract Control](AbstractControl.md)
716
Base class for [FormControl](FormControl.md), [FormGroup](FormGroup.md), and [FormArray](FormArray.md).
817

0 commit comments

Comments
 (0)