StatusChanges In Angular Forms
In this article, We will learn about the how to use StatusChanges in Angular Forms. Angular forms raise the StatusChanges event anytime the validation status of the FormControl, FormGroup, or FormArray is calculated. You can subscribe to it because it returns an observable. The observable receives the control's most recent status. Every time a change is made to the control, Angular performs a validation check. It also produces a list of validation problems, after which the status is changed to INVALID. If there are no mistakes, the status is changed to VALID.
How to use StatusChanges
Three building blocks make up the Angular Forms. FormControl, FormGroup, and FormArray are three types of forms. The AbstractControl base class is extended by all of these controllers. The StatusChanges event is implemented by the AbstractControl base class.
We can subscribe to StatusChanges by obtaining the control's reference and doing so as shown below.
- this.reactiveForm.get("firstname").statusChanges.subscribe(newStaus => {
- console.log('firstname status changed')
- console.log(newStaus)
- })
You can also sign up for the top-level form, which is displayed below.
- this.reactiveForm.statusChanges.subscribe(newStaus => {
- console.log('form Status changed event')
- console.log(newStaus)
- })
StatusChanges Example
- reactiveForm = new FormGroup({
- firstname: new FormControl('', [Validators.required]),
- lastname: new FormControl(),
- address: new FormGroup({
- city: new FormControl(),
- street: new FormControl(),
- pincode: new FormControl()
- })
- })
StatusChanges of FormControl
- this.reactiveForm.get("firstname").statusChanges.subscribe(newStatus => {
- console.log('firstname status changed')
- console.log(newStatus) //latest status
- console.log(this.reactiveForm.get("firstname").status) //latest status
- })
- this.reactiveForm.get("firstname").statusChanges.subscribe(newStatus=> {
- console.log('firstname status changed')
- console.log(newStatus) //latest status
- console.log(this.reactiveForm.get("firstname").status) //latest status
- console.log(this.reactiveForm.status) //Previous status
- })
You can get around this by using setTimeout to wait for the next tick, as illustrated below.
- this.reactiveForm.get("firstname").statusChanges.subscribe(newStatus=> {
- console.log('firstname status changed')
- console.log(newStatus) //latest status
- console.log(this.reactiveForm.get("firstname").status) //latest status
- console.log(this.reactiveForm.status) //Previous status
- setTimeout(() => {
- console.log(this.reactiveForm.status) //latest status
- })
- })
StatusChanges of FormGroup
- this.reactiveForm.get("address").statusChanges.subscribe(newStaus => {
- console.log('address status changed')
- console.log(newStaus)
- })
StatusChanges of Form
- this.reactiveForm.statusChanges.subscribe(newStaus => {
- console.log('form status changed')
- console.log(newStaus)
- })
emitEvent & StatusChanges
- this.reactiveForm.get("firstname").setValue("", { emitEvent: false });
onlySelf & StatusChanges
- this.reactiveForm.get("firstname").setValue("", { onlySelf: true });
- import { Component, OnInit } from '@angular/core';
- import { FormGroup, FormControl, Validators } from '@angular/forms'
- import { timeout } from 'q';
- @Component({
- templateUrl: './reactive.component.html',
- })
- export class ReactiveComponent implements OnInit {
- title = 'Reactive Forms';
- reactiveForm = new FormGroup({
- firstname: new FormControl('', [Validators.required]),
- lastname: new FormControl(),
- address: new FormGroup({
- city: new FormControl(),
- street: new FormControl(),
- pincode: new FormControl()
- })
- })
- onSubmit() {
- //console.log(this.reactiveForm.value);
- }
- ngOnInit() {
- this.reactiveForm.get("firstname").statusChanges.subscribe(newStatus=> {
- console.log('firstname status changed')
- console.log(newStatus)
- console.log(this.reactiveForm.get("firstname").status)
- console.log(this.reactiveForm.status)
- setTimeout(() => {
- console.log(this.reactiveForm.status)
- })
- })
- this.reactiveForm.get("address").statusChanges.subscribe(newStatus=> {
- console.log('address status changed')
- console.log(newStatus)
- })
- this.reactiveForm.statusChanges.subscribe(newStatus=> {
- console.log('form status changed')
- console.log(newStatus)
- })
- }
- setValue() {
- let contact = {
- firstname: "Rahul",
- lastname: "Dravid",
- address: {
- city: "Bangalore",
- street: "Brigade Road",
- pincode: "600070"
- }
- };
- this.reactiveForm.setValue(contact);
- }
- setAddress() {
- this.reactiveForm.get("address").setValue(
- {
- city: "Bangalore",
- street: "Brigade Road",
- pincode: "600070"
- }
- );
- }
- setFirstname() {
- this.reactiveForm.get("firstname").setValue("Saurav")
- }
- withoutOnlySelf() {
- this.reactiveForm.get("firstname").setValue("");
- }
- withOnlySelf() {
- this.reactiveForm.get("firstname").setValue("", { onlySelf: true });
- }
- withEmitEvent() {
- this.reactiveForm.get("firstname").setValue("Sachin");
- }
- withoutEmitEvent() {
- this.reactiveForm.get("firstname").setValue("", { emitEvent: false });
- }
- reset() {
- this.reactiveForm.reset();
- }
- }
The following code is complete code of the reactive.component.html
- <h3>{{title}}</h3>
- <div style="float: left; width:50%;">
- <form [formGroup]="reactiveForm" (ngSubmit)="onSubmit()" novalidate>
- <p>
- <label for="firstname">First Name </label>
- <input type="text" id="firstname" name="firstname" formControlName="firstname">
- <label for="lastname">Last Name </label>
- <input type="text" id="lastname" name="lastname" formControlName="lastname">
- </p>
- <div formGroupName="address">
- <p>
- <label for="city">City</label>
- <input type="text" class="form-control" name="city" formControlName="city">
- <label for="street">Street</label>
- <input type="text" class="form-control" name="street" formControlName="street">
- <label for="pincode">Pin Code</label>
- <input type="text" class="form-control" name="pincode" formControlName="pincode">
- </p>
- </div>
- <button>Submit</button>
- </form>
- <div>
- <button type="button" (click)="setValue()">SetValue</button>
- <button type="button" (click)="setAddress()">Address</button>
- <button type="button" (click)="setFirstname()">First Name</button>
- </div>
- <div>
- <button type="button" (click)="withoutOnlySelf()">Without Only Self</button>
- <button type="button" (click)="withOnlySelf()">With Only Self</button>
- </div>
- <div>
- <button type="button" (click)="withouEmitEvent()">Without EmitEvent</button>
- <button type="button" (click)="withEmitEvent()">With EmitEvent</button>
- </div>
- </div>
- <div style="float: right; width:50%;">
- <h3>Form Status</h3>
- <b>status : </b>{{reactiveForm.status}}
- <b>valid : </b>{{reactiveForm.valid}}
- <b>invalid : </b>{{reactiveForm.invalid}}
- <b>touched : </b>{{reactiveForm.touched}}
- <b>untouched : </b>{{reactiveForm.untouched}}
- <b>pristine : </b>{{reactiveForm.pristine}}
- <b>dirty : </b>{{reactiveForm.dirty}}
- <b>disabled : </b>{{reactiveForm.disabled}}
- <b>enabled : </b>{{reactiveForm.enabled}}
- <h3>Form Value</h3>
- {{reactiveForm.value |json}}
- </div>
The following code is complete code of the app.component.html
- <h3>Angular StatusChanges Example</h3>
- <ul>
- <li>
- <a [routerLink]="['/template']" routerLinkActive="router-link-active" >Template</a>
- </li>
- <li>
- <a [routerLink]="['/reactive']" routerLinkActive="router-link-active" >Reactive</a>
- </li>
- </ul>
- <router-outlet></router-outlet>
The following code is complete code of the app.component.ts
- import { Component} from '@angular/core';
- @Component({
- selector: 'app-root',
- templateUrl: './app.component.html',
- styleUrls: ['./app.component.css']
- })
- export class AppComponent {
- }
- The following code is complete code of the app.module.ts
- import { BrowserModule } from '@angular/platform-browser';
- import { NgModule } from '@angular/core';
- import { FormsModule, ReactiveFormsModule } from '@angular/forms';
- import { AppRoutingModule } from './app-routing.module';
- import { AppComponent } from './app.component';
- import { TemplateComponent } from './template-component';
- import { ReactiveComponent } from './reactive.component';
- @NgModule({
- declarations: [
- AppComponent,TemplateComponent,ReactiveComponent
- ],
- imports: [
- BrowserModule,
- AppRoutingModule,
- FormsModule,
- ReactiveFormsModule
- ],
- providers: [],
- bootstrap: [AppComponent]
- })
- export class AppModule { }
StatusChanges in Template Driven Forms
- @ViewChild('templateForm',null) templateForm: NgForm;
- import { Component, ViewChild, ElementRef, OnInit, OnDestroy } from '@angular/core';
- import { NgForm } from '@angular/forms';
- @Component({
- templateUrl: './template.component.html',
- })
- export class TemplateComponent implements OnInit {
- title = 'Template driven forms';
- @ViewChild('templateForm',null) templateForm: NgForm;
- contact: contact;
- onSubmit() {
- console.log(this.templateForm.value);
- }
- ngOnInit() {
- setTimeout(() => {
- this.templateForm.control.get("firstname").statusChanges.subscribe(newStatus=> {
- console.log('firstname status changed')
- console.log(newStatus)
- console.log(this.templateForm.control.get("firstname").status)
- console.log(this.templateForm.control.status)
- setTimeout(() => {
- console.log(this.templateForm.control.status)
- })
- })
- this.templateForm.control.get("address").statusChanges.subscribe(newStatus => {
- console.log('address status changed')
- console.log(newStatus)
- })
- this.templateForm.control.statusChanges.subscribe(newStatus=> {
- console.log('form status changed')
- console.log(newStatus)
- })
- });
- }
- setValue() {
- let contact = {
- firstname: "Rahul",
- lastname: "Dravid",
- address: {
- city: "Bangalore",
- street: "Brigade Road",
- pincode: "600070"
- }
- };
- this.templateForm.setValue(contact);
- }
- setAddress() {
- let address= {
- city: "Bangalore",
- street: "Brigade Road",
- pincode: "600070"
- };
- this.templateForm.control.get("address").setValue(address);
- };
- setFirstname() {
- this.templateForm.control.get("firstname").setValue("Saurav")
- }
- withoutOnlySelf() {
- this.templateForm.control.get("firstname").setValue("");
- }
- withOnlySelf() {
- this.templateForm.control.get("firstname").setValue("", { onlySelf: true });
- }
- withouEmitEvent() {
- this.templateForm.control.get("firstname").setValue("Sachin");
- }
- withEmitEvent() {
- this.templateForm.control.get("firstname").setValue("", { emitEvent: false });
- }
- reset() {
- this.templateForm.reset();
- }
- }
- export class contact {
- firstname:string;
- lastname:string;
- gender:string;
- email:string;
- isMarried:boolean;
- country:string;
- address: {
- city:string;
- street:string;
- pincode:string;
- }
- }
Now, add the following code into the template-component.html
- <h3>{{title}}</h3>
- <div style="float: left; width:50%;">
- <form #templateForm="ngForm" (ngSubmit)="onSubmit(templateForm)">
- <p>
- <label for="firstname">First Name </label>
- <input type="text" id="firstname" name="firstname" #fname="ngModel" ngModel>
- </p>
- <p>
- <label for="lastname">Last Name </label>
- <input type="text" id="lastname" name="lastname" ngModel>
- </p>
- <div ngModelGroup="address">
- <p>
- <label for="city">City</label>
- <input type="text" id="city" name="city" ngModel>
- <label for="street">Street</label>
- <input type="text" id="street" name="street" ngModel>
- <label for="pincode">Pin Code</label>
- <input type="text" id="pincode" name="pincode" ngModel>
- </p>
- </div>
- <button>Submit</button>
- </form>
- <div>
- <button type="button" (click)="setValue()">SetValue</button>
- <button type="button" (click)="setAddress()">Address</button>
- <button type="button" (click)="setFirstname()">First Name</button>
- </div>
- <div>
- <button type="button" (click)="withoutOnlySelf()">Without Only Self</button>
- <button type="button" (click)="withOnlySelf()">With Only Self</button>
- </div>
- <div>
- <button type="button" (click)="withouEmitEvent()">Without EmitEvent</button>
- <button type="button" (click)="withEmitEvent()">With EmitEvent</button>
- </div>
- </div>
- <div style="float: right; width:50%;">
- <h3>Form Status</h3>
- <b>status : </b>{{templateForm.status}}
- <b>valid : </b>{{templateForm.valid}}
- <b>invalid : </b>{{templateForm.invalid}}
- <b>touched : </b>{{templateForm.touched}}
- <b>untouched : </b>{{templateForm.untouched}}
- <b>pristine : </b>{{templateForm.pristine}}
- <b>dirty : </b>{{templateForm.dirty}}
- <b>disabled : </b>{{templateForm.disabled}}
- <b>enabled : </b>{{templateForm.enabled}}
- <h3>Form Value</h3>
- {{templateForm.value | json }}
- </div>