Angular
reactive forms, also known as model-driven forms, offers an easy way to use
reactive patterns and validations. They follow the reactive programming style
that supports an explicit data management flow between non-UI data models
(frequently retrieved from a server) and a UI-oriented form model that keeps
the states and values of HTML controls on the app screen.
When
coding reactive forms, we will avoid directives like required,
ngModel, NgForm and such. The idea is that we actually use
the underlying APIs to do it for us. In a sense, instead binding Object models
to directives like it happens in template-driven forms, we create our own
instances inside a component class and build our very own JavaScript models.
This approach has a lot more power and is extremely productive to work with
since it allows us to write expressive code (a very testable one that keeps all
the logic in the same place) instead of dividing it over different form
templates.
With
reactive forms, you will be able to create and manipulate form control objects
directly in the Component. Since the component class has access to the form
control structure and the data model, you can push data model values into the
form controls as well as pull values that have been changed by the user. The
component is able to observe changes in the form control state and react to
them. This is specially useful for showing a validation message.
One
of the advantages that working directly with form control objects brings you is
that value and validity updates are always synchronous and under your control.
You won’t find the timing issues that sometimes affect a template-driven form.
Also, reactive forms tend to be easier to unit test.
Reactive
Form Model Setup
Step-1: Create a Reactive Form
Component: Command
to create a Reactive Form component is:
ng g c reactive-form --spec false
Step-2: import
ReactiveFormsModule in app.module.ts file: As we know that Reactive
forms make use of the "ReactiveFormsModule". So we include this in app.module.ts
file as below:
import { ReactiveFormsModule } from '@angular/forms';
Step-3: Now write
code for reactive-form.component.ts, But
first, add FormControl and FormGroup
module in ReactiveFormComponent.ts file as these are basic building blocks of Reactive Forms.
import { FormGroup, FormControl } from '@angular/forms';
FormControl:
it tracks the value and validity status of an angular form control. It matches
to an HTML form control like an input.
FormGroup:
it tracks the value and validity state of each input control. It aggregates the
values of each child FormControl into one object, using the name of
each form control as the key.
Step-4: Code for reactive-form.component.ts
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
@Component({
selector: 'app-reactive-form',
templateUrl: './reactive-form.component.html',
styleUrls: ['./reactive-form.component.css']
})
export class ReactiveFormComponent implements OnInit {
courseForm: FormGroup; // create a property of type formgroup
constructor() {}
ngOnInit() {
this.initForm();
}
onSubmit() {
console.log(this.courseForm);
}
private initForm() {
this.courseForm = new FormGroup({
courseName: new FormControl(),
courseDesc: new FormControl(),
courseAmount: new FormControl()
});
}
}
Step-5: Now write
following code in reactive-form.component.html
<div class="container">
<h3 class="text-center text-danger">Reactive Form</h3>
<br />
<div class="row">
<div class="col-xs-12">
<form [formGroup]="courseForm" (ngSubmit)="onSubmit()">
<div class="row">
<div class="col-sm-4 form-group">
<label for="courseName">Course Name</label>
<input
type="text"
id="courseName"
class="form-control"
formControlName="courseName"
/>
</div>
<div class="col-sm-4 form-group">
<label for="courseDesc">Course Description</label>
<input
type="text"
id="courseDesc"
class="form-control"
formControlName="courseDesc"
/>
</div>
<div class="col-sm-4 form-group">
<label for="courseAmount">Course Amount</label>
<input
type="number"
id="courseAmount"
class="form-control"
formControlName="courseAmount"
/>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<button class="btn btn-success m-3" type="submit">Add</button>
</div>
</div>
</form>
</div>
</div>
</div>
<br /><br />
<!-- Reactive Form Validation -->
<table border="1">
<tr>
<th style="padding: 10px">FormGroup</th>
<th style="padding: 10px">FormControl(courseName)</th>
</tr>
<tr>
<!-- Form Validation -->
<td style="padding: 10px">
touched : {{ courseForm.touched }} <br />
dirty : {{ courseForm.dirty }} <br />
valid : {{ courseForm.valid }} <br />
Form Values : {{ courseForm.value | json }}
</td>
<!—Input Controls Validation -->
<td style="padding: 10px">
touched : {{ courseForm.get('courseName').touched }} <br />
dirty : {{ courseForm.get('courseName').dirty }} <br />
valid : {{ courseForm.get('courseName').valid }} <br />
courseName Value : {{ courseForm.get('courseName').value }}
</td>
</tr>
</table>
Code Explanation:
courseForm: FormGroup; // create a property of type formgroup
1.
In .ts file First
we create a variable of reactive
form courseForm: form FormGroup;
2.
Then we create a private method private initForm() and call this in the ngOnInit() life cycle
hook, so that it will be called as the component initialize.
3.
In private initForm() create an instance FormGorup as courseForm
and use these in Template to create Form. Similarly we also create instances of
FormControl as courseName,
courseDesc and courseAmount
respectively to create input for taking values from the user.
4. In OnSubmit() function we are getting form values
and send it to the console.
5. In order to
display form value in View it-self, we use local variable to display the values
as json object using the command courseForm.value
| json.
6. In template
we use formGroup
property for form and formControlName as an attribute for create
instance of input controls for collecting form values.
Code Output:
Reactive Form Validation
In
reactive forms, instead of adding validators through attributes in the template
(like it happens with template-driven forms), you add validator functions
directly to the form control model in the angular component class. Angular will
call these functions whenever the value of the control changes.
You
can choose between writing your own validator functions and using some of the
Angular built-in validators by importing Validaors module .
import { FormGroup, FormControl, Validators } from '@angular/forms';
Now update your code in
reactive-form.component.ts file with following code:
private initForm() {
this.courseForm = new FormGroup({
courseName: new FormControl('', Validators.required),
courseDesc: new FormControl('', Validators.required),
courseAmount: new FormControl()
});
}
Angular
is constantly updating the state of both the form and the input fields.
To validate form use the code:
touched : {{ courseForm.touched }} // Form-Name.touched
touched : {{ courseForm.touched }} // Form-Name.touched
To validate form control use the
code:
touched : {{ courseForm.get('courseName').touched }}
touched : {{ courseForm.get('courseName').touched }}
Note: get('courseName')
is used to
find the input control name.