ValueChanges In Angular Forms
In this article, We will learn about the how to use ValueChanges in Angular Forms. When the value of the FormControl, FormGroup, or FormArray changes, the ValueChanges event is raised by the Angular forms. You can subscribe to it because it returns an observable. The control's most recent value is passed to the observable. It allows us to track and respond to changes in the value in real time. It can be used to validate a value, calculate calculated fields, and so on.
How to use ValueChanges
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 ValueChanges event is implemented by the AbstractControl base class.
We can subscribe to ValueChanges by obtaining the control's reference and doing so as indicated below.
this.reactiveForm.get("firstname").valueChanges.subscribe(x => { console.log('firstname value changed') console.log(x) })
You can also sign up for the top-level form, which is displayed below.
this.reactiveForm.valueChanges.subscribe(x => { console.log('form value changed') console.log(x) })
ValueChanges Example
reactiveForm = new FormGroup({ firstname: new FormControl('', [Validators.required]), lastname: new FormControl(), address: new FormGroup({ city: new FormControl(), street: new FormControl(), pincode: new FormControl() }) })
ValueChanges of FormControl
this.reactiveForm.get("firstname").valueChanges.subscribe(selectedValue => { console.log('firstname value changed') console.log(selectedValue) //latest value of firstname console.log(this.reactiveForm.get("firstname").value) //latest value of firstname })
ValueChanges shows previous value
this.reactiveForm.get("firstname").valueChanges.subscribe(selectedValue => { console.log('firstname value changed') console.log(selectedValue) console.log(this.reactiveForm.get("firstname").value) console.log(this.reactiveForm.value) //still shows the old first name })
You can get around this by using setTimeout to wait for the next tick, as illustrated below.
this.reactiveForm.get("firstname").valueChanges.subscribe(selectedValue => { console.log('firstname value changed') console.log(selectedValue) console.log(this.reactiveForm.get("firstname").value) console.log(this.reactiveForm.value) //shows the old first name setTimeout(() => { console.log(this.reactiveForm.value) //shows the latest first name }) })
ValueChanges of FormGroup
this.reactiveForm.get("address").valueChanges.subscribe(selectedValue => { console.log('address changed') console.log(selectedValue) })
ValueChanges of Form
this.reactiveForm.valueChanges.subscribe(selectedValue => { console.log('form value changed') console.log(selectedValue) })
EmitEvent & ValueChanges
this.reactiveForm.get("firstname").setValue("", { emitEvent: false });
OnlySelf & ValueChanges
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").valueChanges.subscribe(selectedValue => { console.log('firstname value changed') console.log(selectedValue) console.log(this.reactiveForm.get("firstname").value) console.log(this.reactiveForm.value) setTimeout(() => { console.log(this.reactiveForm.value) }) }) this.reactiveForm.get("address").valueChanges.subscribe(selectedValue => { console.log('address changed') console.log(selectedValue) }) this.reactiveForm.valueChanges.subscribe(selectedValue => { console.log('form value changed') console.log(selectedValue) }) } 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> <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> </form> </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 ValueChanges 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 { }
ValueChanges 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").valueChanges.subscribe(selectedValue => { console.log('firstname value changed') console.log(selectedValue) console.log(this.templateForm.control.get("firstname").value) console.log(this.templateForm.control.value) setTimeout(() => { console.log(this.templateForm.control.value) }) }) this.templateForm.control.get("address").valueChanges.subscribe(selectedValue => { console.log('address changed') console.log(selectedValue) }) this.templateForm.valueChanges.subscribe(selectedValue => { console.log('form value changed') console.log(selectedValue) }) }); } 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, put the below code under the template-component.html file
<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> <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> </form> </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>