This page looks best with JavaScript enabled

Reactive form programming in Angular 7

 ·  ☕ 10 min read  ·  ✍️ Adesh

In Angular, there are two ways to work with web forms: template driven forms and reactive forms. In template driven form, we use angular directives to build the internal representation of form in the html template file. Most of the code is written in html template file, making it sometimes difficult to understand and test.

In reactive form, we build our form design in the component class instead of component template file. This provides us more flexibility, keep your logic in component class file, instead of component template file. This makes our component template clean and simple.

Benefits

There are few benefits of using reactive form over the template forms. These are:

  • Add form controls more dynamically
  • Add form validation dynamically
  • Using custom validations

Reactive Form Programming

To start with reactive form programming, you should know about these classes:

  • FormControl - Tracks the value and validation status of an individual form control.
  • FormGroup  - Tracks the value and validity state of a group of FormControl instances.
  • FormBuilder - A service that is used to build FormGroups easily.

Setting the project

1
ng new reactiveform
1
? **Would you like to add Angular routing?** Yes
1
? **Which stylesheet format would you like to use?** CSS

Add the ReactiveFormsModule in the Module file

In order to use Reactive Forms in your app, we have to first import ReactiveFormsModule in app.module.ts from @angular/forms, and then add in the @NgModule imports array.

app.module.ts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    ReactiveFormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

A Basic Control: FormControl

Let’s first create our generalInfo component in the app.

1
ng generate component generalInfo

To create any form control, we first have to import FormControl from @angular/forms package into our component.

After importing FormControl, we will create an instance of our form control firstName.

We can use the FormControl constructor to set the initial value of the control. Here, we are setting the empty string in the constructor.

Placing form control in template

After creating our first form control firstName in the controller file, it’s time to place this control in our html template file. Let’s put our form control in template.

general-info.component.html

1
2
3
<label>
  FirstName : <input type="text" [formControl] = "firstName">
</label>

Using the template binding syntax, we bind our form control to the firstName input box in the template.

Displaying our component

In order to display our component in the browser window, we are going to place it in the app.component.html file.

app.component.html

1
2
3
4
5
6
7
8
9
<!--The content below is only a placeholder and can be replaced.-->
<div style="text-align:center">
  <h1>
    Welcome to {{ title }}!
  </h1>
 
  <app-general-info></app-general-info>

<router-outlet></router-outlet>

Notice line 7, we have placed our component <app-general-info></app-general-info> in this template. Now, let’s see how our form looks like in browser window.

reactive form

Accessing Form Control Values

In reactive forms, you can access any form control state and value at any point of time. You can then manipulate the form control values from the component class or component template. Let’s see how to display our form control value in component template file.

Accessing form control value in template file

You can access and display the form control value using the value property.

general-info.component.html

1
<p>First Name: {{firstName.value}}</p>

The value on the form will change as you type in the form input control firstName.

form control value

As you can see in above screenshot, as we type zeptobook in our form control firstName, it is immediately displayed below.

Accessing and setting the form control value in component class

Like you access form control value in component template file, you can access it in component class programmatically. You can manipulate value here in component class file.

A form control instance has a setValue() method, that you can use to update the form control value from the component class file.

Let’s see how to set the control value programmatically. In the general-info.component.ts file, we have a method updateFirstName(), and set the form control value ZeptoBook using this.firstName.setValue('ZeptoBook').

general-info.component.ts

1
2
3
updateFirstName(){
    this.firstName.setValue('ZeptoBook');
  }

general-info.component.html

Now, we have to write code to call this method from button click event. Let’s create a button and attach updateFirstName() method to button’s click event.

1
2
3
<p>
  <button (click)="updateFirstName()">Update First Name</button>
</p>

Now, when user click on this button, it will set the form control value to ZeptoBook and update this in input box and label.

update form control value

Setting initial value in form control

We can also set some initial value while creating the form control. Remember, we put empty string while creating our firstName form control. Now, let’s see how to use form control constructor to initialize the value in the form control.

general-info.component.ts

1
age = new FormControl(18);

Here, we have created an age form control and initialized its value to 18 in its constructor. Accessing the age form control in the component template file.

general-info.component.html

1
2
3
4
<label>
  Age : <input type="text" [formControl] = "age">
</label>
<p>Age: {{age.value}}</p>

Now, open the browser and see the output.

reactive form programming

Here you can see, Age input box and label is showing the initialized value of 18, which you can change anytime.

Now, let’s have a look at complete code.

general-info.component.ts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import { Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';

@Component({
  selector: 'app-general-info',
  templateUrl: './general-info.component.html',
  styleUrls: ['./general-info.component.css']
})
export class GeneralInfoComponent implements OnInit {

  constructor() { }

  ngOnInit() {}

  firstName = new FormControl('');
  age = new FormControl(18);

  updateFirstName(){
    this.firstName.setValue('ZeptoBook');
  }
}

general-info.component.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<p>
  Our General Info Component
</p>
<label>
  FirstName : <input type="text" [formControl] = "firstName">
</label>
<p>First Name: {{firstName.value}}</p>
<p>
  <button (click)="updateFirstName()">Update First Name</button>
</p>
<label>
  Age : <input type="text" [formControl] = "age">
</label>
<p>Age: {{age.value}}</p>

Grouping Form Controls: FormGroup

Above we read about basic form control, now let’s move forward to group of form controls called FormGroup. FormGroup is used to track the value and validation state of form control.

Let’s create a new component app-form-group to demonstrate FormGroup.

1
ng generate component formGroup

Import FormGroup and FormControl

After generating our new component, it’s time to import these classes in component class.

form-group.component.ts

1
import { FormGroup, FormControl } from '@angular/forms';

Create FormGroup instance

Let’s create a property in our component class called sampleForm and set the property to a new Form Group instance. In the Form Group instance constructor, we have created these form control instances.

form control instances in form group

  • firstName
  • lastName
  • address
  • city

form-group.component.ts

1
2
3
4
5
6
sampleForm = new FormGroup({
    firstName: new FormControl(''),
    lastName: new FormControl(''),
    address: new FormControl(''),
    city: new FormControl('')
  });

Attaching FormGroup model with component view

Once we created sampleForm control in component class, it’s time to bind FormGroup model to our component view template.

Let’s see the syntax how to bind the model to view.

form-group.component.html

1
2
3
4
5
6
7
8
<form [formGroup] = "sampleForm" (ngSubmit)="onSubmit()">
  <label>First Name: <input type="text" formControlName="firstName"></label><br/>
  <label>Last Name: <input type="text" formControlName="lastName"></label><br/>
  <label>Address: <input type="text" formControlName="address"></label><br/>
  <label>City: <input type="text" formControlName="city"></label><br/>
  <br/>
  <button type="submit">Submit</button>
</form>

We have add a submit button, and add ngSubmit event. On pressing submit event, we are firing onSubmit() function of the component class. Let’s see the complete code.

form-group.component.ts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';

@Component({
  selector: 'app-form-group',
  templateUrl: './form-group.component.html',
  styleUrls: ['./form-group.component.css']
})
export class FormGroupComponent implements OnInit {

  constructor() { }

  ngOnInit() {}

  sampleForm = new FormGroup({
    firstName: new FormControl(''),
    lastName: new FormControl(''),
    address: new FormControl(''),
    city: new FormControl('')
  });

  onSubmit(){
    console.log(this.sampleForm.value);
  }
}

form-group.component.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<p>
  form-group works!
</p>
<form [formGroup] = "sampleForm" (ngSubmit)="onSubmit()">
  <label>First Name: <input type="text" formControlName="firstName"></label><br/>
  <label>Last Name: <input type="text" formControlName="lastName"></label><br/>
  <label>Address: <input type="text" formControlName="address"></label><br/>
  <label>City: <input type="text" formControlName="city"></label><br/>
  <br/>
  <button type="submit">Submit</button>
</form>

Also, in order to display this component in browser, I have commented our previous component app-general-info, and placed our app-form-group component. See the commented line 7.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<!--The content below is only a placeholder and can be replaced.-->
<div style="text-align:center">
  <h1>
    Welcome to {{ title }}!
  </h1>
 
  <!-- <app-general-info></app-general-info> -->
  <app-form-group></app-form-group>

<router-outlet></router-outlet>

Now, once you open your browser, and see the screen, it looks like this.

form group control

On submit, output will be rendered in browser console.window.

form group control

Now, see the red marked area in console log.

Easy way to generate Form Control: FormBuilder

When we have multiple forms, then it become very tedious and repetitive to create form controls. FormBuilder service is a easy way for generating form controls.

Let’s create a new component app-form-group to demonstrate FormGroup.

1
ng generate component formBuilder

Import FormBuilder

After generating our new component, it’s time to import these FormBuilder in component class.

form-builder.component.ts

1
import { FormBuilder } from '@angular/forms';

Inject FormBuilder in Constructor

form-builder.component.ts

1
constructor(private fb: FormBuilder) { }

Creating the form controls

Here we are going to create a simple login form, having username and password form controls in component class.

1
2
3
4
builderForm = this.fb.group({
    userName: [''],
    password: ['']
  });

Now, notice the syntax, the declaration of FormGroup and FormControl are now implicit. This saves a lot of our code. We only need to have fields name with the default values.

Attaching FormBuilder model with component view

form-builder.component.html

1
2
3
4
5
6
7
8
<p>
  form-builder works!
</p>
<form [formGroup]="builderForm" (ngSubmit) = "login()">
<label>User Name: <input type="text" name="username" id="username" formControlName="userName"></label><br/>
<label>Password: <input type="password" name="password" id="password" formControlName="password"></label><br/>
<button type="submit">Submit</button>
</form>

If you see, we have a submit button, and attached login() function to this submit button. See the login() function in the component class file.

1
2
3
login(){
    console.log(this.builderForm.value);
  }

Add this component in app.component.html file

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<!--The content below is only a placeholder and can be replaced.-->
<div style="text-align:center">
  <h1>
    Welcome to {{ title }}!
  </h1>
 
  <!-- <app-general-info></app-general-info> -->
  <!-- <app-form-group></app-form-group> -->
  <app-form-builder></app-form-builder>

<router-outlet></router-outlet>

Open the browser, and see the result.

Form Builder

See the red marked console log. You can see the username and password fields values. The complete code is:

form-builder.component.ts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { Component, OnInit } from '@angular/core';
import { FormBuilder } from '@angular/forms';

@Component({
  selector: 'app-form-builder',
  templateUrl: './form-builder.component.html',
  styleUrls: ['./form-builder.component.css']
})
export class FormBuilderComponent implements OnInit {

  constructor(private fb: FormBuilder) { }

  ngOnInit() {}

  builderForm = this.fb.group({
    userName: [''],
    password: ['']
  });

  login(){
    console.log(this.builderForm.value);
  }

}

form-builder.component.html

1
2
3
4
5
6
7
8
<p>
  form-builder works!
</p>
<form [formGroup]="builderForm" (ngSubmit) = "login()">
<label>User Name: <input type="text" name="username" id="username" formControlName="userName"></label><br/>
<label>Password: <input type="password" name="password" id="password" formControlName="password"></label><br/>
<button type="submit">Submit</button>
</form>

In this way, we created our simple form using the FormBuilder.

Summary

In this post, we learned about reactive form programming using the FormControl, FormGroup and FormBuilder. These are more powerful way of creating forms as compared to template driven approach. You can do lot of things in the component class file, making the component template file light and thin, containing only html syntax. This approach is also useful for testing purpose.

I hope you enjoyed more reading this blog.

Reference

https://angular.io/guide/reactive-forms

Read more:

Share on

Adesh
WRITTEN BY
Adesh
Technical Architect