Getting Started With Angular Reactive Forms

Reactive Forms In Angular

In today’s world, most of the application contains the forms. It can be a simple form or can be a complex one.

So forms are a crucial part of any application that we are building.

In this post, we’ll learn how to create Reactive Forms in Angular.

Angular provides two different ways to works with the form:

  • Template Driven Forms
  • Reactive Forms(Model Driven Forms)


Template drive form is the same way that we were using in Angular1(AngularJs). It binds the data using data model property in the component, using ngModel directive. In this approach angular updates the mutable data model with user changes.
Reactive Forms uses totally a different way to create forms.
It uses immutable approach to manage the state of the form. so when the user changes anything in the form will result in a new form state.

We’ll convert this article into Angular Reactive Form Series. so that it will be clearer to get the better understanding of angular reactive forms.

This series contains a list of articles as follows:

1.  Angular Reactive Forms: Getting Started.
2.  Angular Reactive Forms: Dynamic Control with Form Array [Coming soon].
3.  Angular Reactive Forms: Built-in Validators.
4.  Angular Reactive Forms: Custom Validator.

Table Of Contents:

1) Importing ReactiveFormsModule.
2) Building Forms Using Reactive Forms.
      – FormControl
      – FormGroup
      – FormBuilder
      – FormArray
3) Managing Control Values.
4) Saving Form Data.
5) Managing Form Values.
6) Creating FormControl with FormBuilder.

Importing ReactiveFormsModule

To get started with Reactive Forms, we need to import ReactiveFormsModule from @angular/forms in Main module/Root Module which is app.module.ts.
app.module.ts will look as follows:
<br />import { ReactiveFormsModule } from '@angular/forms';<br /><br />@NgModule({<br />&nbsp; imports: [<br />&nbsp; &nbsp; // other imports ...<br />&nbsp; &nbsp; ReactiveFormsModule<br />&nbsp; ],<br />})<br />export class AppModule { }

Note: If you are using Template Driven Form then you need to import FormsModule in above code instead of ReactiveFormsModule

Building Forms Using Reactive Forms

To get started with Reactive Forms, we need to know about the following classes:

1) FormControl: It is a basic building block when using ReactiveForm. FormControl is an individual form input, which tracks the value and validation status of an individual form control. Input can be a textboxtextarea, checkbox, radio, select etc.

2) FormGroup: A group of form controls, which track the value and validity state of group of FormControl instance.

3) FormArray: It Tracks the value and validity state of an array of FormControl, FormGroup or FormArray instances

4) FormBuilder: It simplifies the form. so instead of using FormControl, FormGroup and FormArray directly, we can use a service API called FormBuilder that simplifies the Form.

FormControl

Basic Example:
<div>ngOnInit() {<br />   this.firstName = new FormControl('');<br />}</div>

Declaring FormControl is easy as you can see in the above code. You need to import FormControl from @angular/forms packages.

To bind firstName property in template html, we can do the following:

<br />&lt;form novalidate&gt;<br />&nbsp; FirstName:<br />&nbsp; &lt;input type="text" [formControl]="firstName"&gt;<br />&lt;/form&gt;<br />

If we have single form control, then we can create it as above. but if we need multiple form controls then we can wrap it in the group, that’s where FormGroup comes into the play.

FormGroup

Basic Example:

<br />&nbsp; ngOnInit() {<br />&nbsp; &nbsp; &nbsp; this.profileGroup = new FormGroup({<br />&nbsp; &nbsp; &nbsp; &nbsp; firstName: new FormControl('Elite'),<br />&nbsp; &nbsp; &nbsp; &nbsp; lastName: new FormControl('Corner')<br />&nbsp; &nbsp; &nbsp; });<br />&nbsp; &nbsp; }<br />

Now we’ve profileGroup which is using FormGroup instance and FormGroup accepts object which contains a group of form control. so in the above example, we have two FormControl instance called firstName and lastName. That’s how we can bind a list of form controls in formgroup.

Binding this FormGroup and FormControl instance is easy task.

We can bind it in our template html file as following:

<br />&lt;form [formGroup]="profileGroup" novalidate&gt;<br />&nbsp; FirstName:<br />&nbsp; &lt;input type="text" formControlName="firstName"&gt;<br />&nbsp; LastName:<br />&nbsp; &lt;input type="text" formControlName="lastName"&gt;<br />&lt;/form&gt;<br />

As you can see in above code that we’ve used [formGroup] to bind the profileGroup
and we have also declared child FormControl instance as formControlName and assign fieldName

Now, We’ll create one component called ProfileComponent and we’ll use profileForm in ProfileComponent.

To create component run the following command:

ng generate component profile 

ProfileForm contains the following Fields:

  • FirstName
  • LastName
  • Email

Our profile.component.ts will looks as follows:

<br />import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core';<br />import { FormGroup, Validators, FormControl } from '@angular/forms';<br /><br />@Component({<br />&nbsp; ...<br />})<br /><br />export class ProfileComponent implements OnInit {<br />&nbsp; profileForm: FormGroup;<br />&nbsp; submitted: boolean = false;<br /><br />&nbsp; constructor() { }<br /><br />&nbsp; ngOnInit() {<br />&nbsp; &nbsp; this.profileForm = new FormGroup({<br />&nbsp; &nbsp; &nbsp; firstName: new FormControl('', Validators.required),<br />&nbsp; &nbsp; &nbsp; lastName: new FormControl('', Validators.required),<br />&nbsp; &nbsp; &nbsp; email: new FormControl('', Validators.email)<br />&nbsp; &nbsp; });<br />&nbsp; }<br /><br />&nbsp; onSubmit() {<br />&nbsp; &nbsp; this.submitted = true;<br />&nbsp; }<br />}<br />

As you can see in above code we’ve initialized profileForm which is FormGroup and it contains three form controls which are firstName, lastName and email.

And also you can see that we’ve added required and email validators as well. If you are new to angular validators, I would recommend reading my previous article: Reactive Forms With Built In Validators Example

Once we create control in component class, we need to associate it with form control element in template. so now we’ll see how we can bind profileForm to it.

As I said earlier we can use [formGroup] to bind profileForm and we can use formControlName for each field as follows :

<br />&lt;form novalidate [formGroup]="profileForm"&gt;<br />&nbsp; First Name :<br />&nbsp; &lt;input type="text" placeholder="First Name" formControlName="firstName"&gt;<br /><br />&nbsp; Last Name :<br />&nbsp; &lt;input type="text" placeholder="Last Name" formControlName="lastName"&gt;<br /><br />&nbsp; Email :<br />&nbsp; &lt;input type="text" placeholder="Email" formControlName="email"&gt;<br /><br />&nbsp; &lt;button type="submit"&gt;Submit&lt;/button&gt;<br />&lt;/form&gt;<br />

The form control is now registered to firstName, lastName and email input element in the template using template binding syntax. It has generated two-way data binding between model and template.

The form control and DOM element communicate with each other: the view reflects changes in the model, and the model reflects changes in the view.

Managing Control Values

Reactive Form allows to manage the state and value of form control instance.
We can get the value of control in following 2 ways:

1) Inside Component class
Using valueChanges observable, which will listen for the value change of form control’s value.

&nbsp;this.profileForm.get('firstName').valueChanges.subscribe((newVal) =&gt; {<br />&nbsp; &nbsp; &nbsp; console.log(newVal);<br />&nbsp; &nbsp; })


For the performance, you can use the above code as following using debounceTime. basically what it does is it will wait for specified time and then it will emit the value.

Form Control Change
<br />import { debounceTime } from "rxjs/operators";&nbsp;<br />this.profileForm.get('firstName').valueChanges<br />&nbsp; &nbsp; &nbsp; .pipe(debounceTime(500))<br />&nbsp; &nbsp; &nbsp; .subscribe((newVal) =&gt; {<br />&nbsp; &nbsp; &nbsp; &nbsp; console.log(newVal);<br />&nbsp; &nbsp; &nbsp; })<br />


Above code will wait for 500ms/0.5s after control value change and then it will emit the value.

The same way we can detect the changes of form. so if any of the fields in the form will be changed then it will emit the value. we just need to remove  get('firstName') from the above code.

Form Change
<br />import { debounceTime } from "rxjs/operators";&nbsp;<br />this.profileForm.valueChanges<br />&nbsp; &nbsp; &nbsp; .pipe(debounceTime(500))<br />&nbsp; &nbsp; &nbsp; .subscribe((newVal) =&gt; {<br />&nbsp; &nbsp; &nbsp; &nbsp; console.log(newVal);<br />&nbsp; &nbsp; &nbsp; })<br />

2) Inside template

 <div>&lt;div&gt;<br />&nbsp; {{profileForm.get('firstName').value}}<br />&lt;/div&gt;</div>

Updating Form Control Value

To update the value of form control we can use setValue function of FormControl.

If we want to change the value of firstName to Elite Corner, we can use it as follows:

<br />this.profileForm.get('firstName').setValue('Elite Corner');<br />

Saving Form Data

The FormGroup directive listens for the submit event emitted by the form element and emits an ngSubmit event that you can bind to a callback function.
<br />&lt;form [formGroup]="profileForm" (ngSubmit)="onSubmit()"&gt;<br />
The above code will call the onSubmit function when form is submitted or submit button is clicked.
In onSubmit function we can check that if submitted form is valid or not and based on that we can do further actions.
<br />onSubmit() {<br />&nbsp; &nbsp; if (this.profileForm.valid) {<br />&nbsp; &nbsp; &nbsp; //form is valid<br />&nbsp; &nbsp; &nbsp; //you can pass it to api endpoint<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; else{<br />&nbsp; &nbsp; &nbsp; //show error<br />&nbsp; &nbsp; }<br />&nbsp; }

That’s how we can check that form is valid or not using this.profileForm.valid

Sometime we have situation where we need the value of each field in the form. we can check it as follows:

<br />  this.profileForm.value<br />

Managing Form Values

While updating the form value we often have two scenarios:
1) Updating part of the model/form (only some fields)
2) Updating whole model/form (all fields)

Updating part of the model/form

Use patchValue while you are updating part of the model.
Don’t use setValue while updating part of the model, otherwise it will throw an error.  

Updating whole model/form

Use setValue when you are updating all the fields of model
If we continue our profileForm example, and if we want to update part of the model, we can do as follows:
<br />this.profileForm.patchValue({<br />&nbsp; &nbsp; &nbsp; firstName: 'abc'<br />&nbsp; &nbsp; })

and to update all the fields:

<br />&nbsp;this.profileForm.setValue({<br />&nbsp; &nbsp; &nbsp; firstName: 'abc',<br />&nbsp; &nbsp; &nbsp; lastName:'xyz',<br />&nbsp; &nbsp; &nbsp; email:'abc@xyz.com'<br />&nbsp; &nbsp; })<br />

Creating Form Control with Form Builder

Creating form control instances manually can become repetitive when dealing with multiple forms. The FormBuilder service provides convenient methods for generating controls to simplify the process of creating form control.
We can create the same profileForm using FormBuilder as following:
Import FormBuilder
<br />import { FormBuilder } from '@angular/forms';<br />


Inject FormBuilder Service

<br />constructor(private fb: FormBuilder) { }<br />


Creating Form

<br />this.profileForm = this.fb.group({<br />&nbsp; &nbsp; &nbsp; firstName: ['', Validators.required],<br />&nbsp; &nbsp; &nbsp; lastName: ['', Validators.required],<br />&nbsp; &nbsp; &nbsp; email: ['', Validators.email]<br />&nbsp; &nbsp; });

In the example above, we’ve use the group() method with the same object as profileName to define the properties in the model. The value for each control name is an array containing the initial value as the first item in the array.

I hope you like this post.

Also Read:

Please share it with your friends if you like it.

Leave a Comment