SetValue And PatchValue In Angular

SetValue And PatchValue In Angular

In this article, we will learn about the how to set model values in Reactive Forms. The AngularFormsModule's setValue and patchValue functions are used to accomplish this. We'll learn more about setValue and patchValue in this post, as well as the differences between them. With an example, we also learn about the onlySelf and emitEvent parameters.


Angular Forms

There are two ways to create forms with Angular. The first employs a template-driven technique, whereas the second employs a reactive forms approach. In our previous article, we went through both of these topics.

FormControl, FormGroup, and FormArray are the three fundamental building pieces of Angular Forms. All of these components have setValue and patchValue methods, and they all operate differently.


SetValue

Syntax of SetValue

setValue(value: { [key: string]: any; }, options: { onlySelf?: boolean; emitEvent?: boolean; } = {}): void

To edit the FormControlFormGroup, or FormArray, we use the SetValue method. When we use SetValue to update a FormGroup or FormArray, the object must exactly match the structure of the FormGroup or FormArray. Otherwise, there will be an error.

PatchValue

Syntax of PatchValue

patchValue(value: { [key: string]: any; }, options: { onlySelf?: boolean; emitEvent?: boolean; } = {}): void

The PatchValue is used to update a portion of the FormGroup or FormArray elements. It only updates the objects that match and ignores the remainder.

onlySelf

When the value of the form changes, Angular examines the form's validation status. The validation process starts with the control whose value was updated and works its way up to the FormGroup top level. This is how things work by default.

There may be times when you don't want Angular to validate the validity of the entire form when you use the setValue or patchValue methods to update a value. The onlySelf=true argument is used to do this. In these circumstances, the angular just verifies the validity of the current control, not any other controls, and the validity checking is not propagated to the parent form group.

emitEvent

Two events are generated by the Angular forms. The first is ValueChanges, and the second is StatusChanges. When the value of the form is modified, the ValueChangesevent is fired. When angular calculates the Form's validation state, the StatusChanges event is fired. This is how things work by default.

By setting emitEvent=false, we can prevent this from occurring.

SetValue Vs PatchValue

The distinction is that with setValue, all controls must be included, whereas with patchValue, some controls can be excluded.

Example

Create a new angular application from scratch. From @angular/forms, import both FormsModule and ReactiveFormsModule. Include it in the metadata for imports as well.

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 { }

Create two new components with their respective templates: reactive.component.ts and template-component.ts. Also, as mentioned below, update the app.component.ts and its template.

Open the app.component.ts file and add the followign code
import { Component} from '@angular/core';
 
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
}

Now, open the app.component.html file and add the following code
<h1>Angular Forms SetValue & PatchValue Example</h1>
 
<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>

SetValue & PatchValue in Reactive Forms

Our template-component.ts and template-component.html files may be found here.

Now, put the following code into the reactive-component.ts file.
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms'
 
 
@Component({
  templateUrl: './reactive.component.html',
})
export class ReactiveComponent implements OnInit {
  title = 'Reactive Forms';
 
 
  countryList: country[] = [
    new country("1", "India"),
    new country('2', 'USA'),
    new country('3', 'England')
  ];
 
  // reactiveForm = new FormGroup({
  //   firstname: new FormControl('Sachin'),
  //   lastname: new FormControl('Tendulkar'),
  //   email: new FormControl('sachin@gmail.com'),
  //   gender: new FormControl('male'),
  //   isMarried: new FormControl(true),
  //   country: new FormControl('2'),
  //   address:new FormGroup({
  //     city: new FormControl("Mumbai"),
  //     street: new FormControl("Perry Cross Rd"),
  //     pincode:new FormControl("400050")
  //   })
  // })
 
  reactiveForm = new FormGroup({
    firstname: new FormControl(),
    lastname: new FormControl(),
    email: new FormControl(),
    gender: new FormControl(),
    isMarried: new FormControl(),
    country: new FormControl(),
    address:new FormGroup({
      city: new FormControl(),
      street: new FormControl(),
      pincode:new FormControl()
    })
  })
 
  onSubmit() {
    console.log(this.reactiveForm.value);
  }
 
  ngOnInit() {
    this.setDefault();
  }
 
  setDefault() {
 
    let contact = {
      firstname: "Sachin",
      lastname: "Tendulkar",
      email: "sachin@gmail.com",
      gender: "male",
      isMarried: true,
      country: "2",
      address: {
        city: "Mumbai",
        street: "Perry Cross Rd",
        pincode: "400050"
      }
    };
 
    this.reactiveForm.setValue(contact);
  }
 
  setValue() {
 
    let contact = {
      firstname: "Rahul",
      lastname: "Dravid",
      email: "rahul@gmail.com",
      gender: "male",
      isMarried: true,
      country: "1",
      address: {
        city: "Bangalore",
        street: "Brigade Road",
        pincode: "600070"
      }
    };
 
    this.reactiveForm.setValue(contact);
  }
 
  setAddress() {
 
    let address= {
      city: "Bangalore",
      street: "Brigade Road",
      pincode: "600070",
    };
 
    this.reactiveForm.get("address").setValue(address);
 
  };
 
  setCountry() {
 
    this.reactiveForm.get("country").setValue("1");
 
  };
 
 
  patchAddress() {
 
    let address= {
      city: "Bangalore",
      street: "Brigade Road",
      //pincode: "600070",
      //firstname:'saurv'
    };
 
    this.reactiveForm.get("address").patchValue(address);
 
  }
 
  patchName() {
    let contact = {
      firstname: "Rahul",
      lastname: "Dravid",
    }
 
    this.reactiveForm.patchValue(contact);
 
  }
 
  reset() {
    this.reactiveForm.reset();
  }
 
}
 
export class country {
  id: string;
  name: string;
 
  constructor(id: string, name: string) {
    this.id = id;
    this.name = name;
  }
}

Now, open the reactive-component.html file and add the following code.
<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">
    </p>
 
    <p>
      <label for="lastname">Last Name </label>
      <input type="text" id="lastname" name="lastname" formControlName="lastname">
    </p>
 
    <p>
      <label for="email">Email </label>
      <input type="text" id="email" name="email" formControlName="email">
    </p>
 
    <p>
      <label for="gender">Geneder </label>
      <input type="radio" value="male" id="gender" name="gender" formControlName="gender"> Male
      <input type="radio" value="female" id="gender" name="gender" formControlName="gender"> Female
    </p>
 
    <p>
      <label for="isMarried">Married </label>
      <input type="checkbox" id="isMarried" name="isMarried" formControlName="isMarried">
    </p>
 
    <p>
      <label for="country">country </label>
      <select id="country" name="country" formControlName="country">
        <option [ngValue]="c.id" *ngFor="let c of countryList">
          {{c.name}}
        </option>
      </select>
    </p>
 
 
    <div formGroupName="address">
 
      <p>
        <label for="city">City</label>
        <input type="text" class="form-control" name="city" formControlName="city">
      </p>
 
      <p>
        <label for="street">Street</label>
        <input type="text" class="form-control" name="street" formControlName="street">
      </p>
 
      <p>
        <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)="setDefault()">Default</button>
    </div>
    <div>
      <button type="button" (click)="setValue()">SetValue</button>
      <button type="button" (click)="setAddress()">Address</button>
      <button type="button" (click)="setCountry()">Country</button>
    </div>
    <div>
      <button type="button" (click)="patchName()">Name</button>
      <button type="button" (click)="patchAddress()">Address</button>
      <button type="button" (click)="reset()">Reset</button>
    </div>
 
 
  </form>
</div>
 
<div style="float: right; width:50%;">
 
  <h3>Form Status</h3>
  <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>

Setting Initial /Default Value

Setting the initial value can be done in two ways. As seen below, one when defining the Form Model as the first argument to the FormControl.
reactiveForm = new FormGroup({
  firstname: new FormControl('Sachin'),
  lastname: new FormControl('Tendulkar'),
  email: new FormControl('sachin@gmail.com'),
  gender: new FormControl('male'),
  isMarried: new FormControl(true),
  country: new FormControl('2'),
  address:new FormGroup({
    city: new FormControl("Mumbai"),
    street: new FormControl("Perry Cross Rd"),
    pincode:new FormControl("400050")
  })
})

Another alternative is to use the ngOnInit method's setValue method. To do so, build a contact object with properties that match the Form Model perfectly, and then use the setValue method as shown below.
ngOnInit() {
  this.setDefault();
}
 
setDefault() {

  let contact = {
    firstname: "Sachin",
    lastname: "Tendulkar",
    email: "sachin@gmail.com",
    gender: "male",
    isMarried: true,
    country: "2",
    address: {
      city: "Mumbai",
      street: "Perry Cross Rd",
      pincode: "400050"
    }
  };

  this.reactiveForm.setValue(contact);
}

The second option has the advantage of allowing you to use setDefault at any time and change the default values.

As previously stated, setValue only works when the properties are same. An error will occur if any of the properties are removed or if a new property is added.

If you comment out the isMarried field, for example, the terminal window will display the following error.

Must supply a value for form control with name: 'isMarried'.

You'll get the following error if you add a new property surname.

Cannot find form control with name: surname.

Nested FormGroup

The setValue method, as previously stated, modifies the entire FormGroup. As a result, we can update the nested form group independently.

We acquire the reference to the address form group in the following example, and then use setValue to change only the address.
setAddress() {

  let address= {
    city: "Bangalore",
    street: "Brigade Road",
    pincode: "600070",
  };

  this.reactiveForm.get("address").setValue(address);

};

The attributes of the address must match exactly once more. Otherwise, there will be an error.

FormControl

Individual control value can be readily set.
setCountry() {
    this.reactiveForm.get("country").setValue("1");
};

PatchValue

When we simply want to change a subset of properties, we use patchValue.

The following example explains how to use the patchValue method to update only city and street values.
patchAddress() {

  let address= {
    city: "Bangalore",
    street: "Brigade Road",
  };

  this.reactiveForm.get("address").patchValue(address);
}
  
patchName() {
let contact = {
  firstname: "Rahul",
  lastname: "Dravid",
}

this.reactiveForm.patchValue(contact); 


Reset Form

reset() {
  this.reactiveForm.reset();
}

OnlySelf Example

When the values of any of the controls on the form change, the angular forms calculate the form's validity state. The validation check begins with the control and continues via the parent controls until it reaches the FormGroup at the top level.

We may instruct Angular not to execute validation on the parent control by using the onlySelf:true option.

We've added a necessary validator to the firstname FormControl, for example. To make the form valid, type something in the firstname field and then leave the value blank, as shown below. The form is no longer valid.
withOutOnlySelf(){
  this.reactiveForm.get("firstname").setValue("");
}

Fill in the firstname field with text to make the form valid again. Try it again, but this time with onlySelf:true. The form continues to be valid.
withOnlySelf(){
  this.reactiveForm.get("firstname").setValue("",{onlySelf:true});
}

emitEvent example

Two events are generated by the Angular forms. The first is ValueChanges, and the second is StatusChanges. The emitEvent:false option, as seen below, can be used to prevent them from occurring.

Subscribe to the StatusChanges and ValueChangesevents at the form and control levels, respectively.
ngOnInit() {
  this.setDefault();

  this.reactiveForm.get("firstname").statusChanges.subscribe(x => {
    console.log('firstname status changes')
  })

  this.reactiveForm.get("firstname").valueChanges.subscribe(x => {
    console.log('firstname value changed')
  })

  this.reactiveForm.statusChanges.subscribe(x => {
    console.log('form status changes')
  })

  this.reactiveForm.valueChanges.subscribe(x => {
    console.log('form value changed')
  })
}

Then update the value of the firstname, and all four events will be triggered.
withouEmitEvent(){
  this.reactiveForm.get("firstname").setValue("Sachin");
}

The events are muted when emitEvent:false is used.
withEmitEvent(){
  this.reactiveForm.get("firstname").setValue("",{emitEvent:false});
}

SetValue & PatchValue in Template-driven Forms

SetValue and patchValue can also be used in template-driven forms. In the angular lesson, we learnt how to achieve it with set Value in template-driven forms.

To accomplish so, we'll need to use the viewChild to get a reference to the Form model in the template.
@ViewChild('templateForm',null) templateForm: NgForm;

Once we have the reference, we can use SetValue and PatchValue, as illustrated in the examples below. Refer to the Angular article Set Value in Template-Driven Forms for a more complete explanation.

Open the template-component.ts file and put the following code
import { Component, ViewChild, ElementRef, OnInit } 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;
 
  countryList: country[] = [
    new country("1", "India"),
    new country('2', 'USA'),
    new country('3', 'England')
  ];
 
  contact: contact;
  
  onSubmit() {
    console.log(this.templateForm.value);
  }
 
  ngOnInit() {
 
    setTimeout(() => { 
      this.setDefault();
    });
    
  }
 
  setDefault() {
 
    let contact = {
      firstname: "Sachin",
      lastname: "Tendulkar",
      email: "sachin@gmail.com",
      gender: "male",
      isMarried: true,
      country: "2",
      address: {
        city: "Mumbai",
        street: "Perry Cross Rd",
        pincode: "400050"
      }
    };
 
    this.templateForm.control.setValue(contact);
  }
 
 
  setValue() {
 
    let contact = {
      firstname: "Rahul",
      lastname: "Dravid",
      email: "rahul@gmail.com",
      gender: "male",
      isMarried: true,
      country: "1",
      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);
 
  };
 
  setCountry() {
 
    let address= {
      city: "Bangalore",
      street: "Brigade Road",
      pincode: "600070"
    };
 
    this.templateForm.control.get("country").setValue("1");
 
  };
 
  
  patchAddress() {
 
    let address= {
      city: "Bangalore",
      street: "Brigade Road",
      //pincode: "600070",
      //firstname:'saurv'
    };
 
    this.templateForm.control.get("address").patchValue(address);
 
  }
 
  patchName() {
    let contact = {
      firstname: "Rahul",
      lastname: "Dravid",
    }
 
    this.templateForm.control.patchValue(contact);
 
  }
 
  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;
  }
} 
 
 
export class country {
  id: string;
  name: string;
 
  constructor(id: string, name: string) {
    this.id = id;
    this.name = name;
  }
}

Now, open the template-component.html file and the following code
<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>
 
    <p>
      <label for="email">Email </label>
      <input type="text" id="email" name="email" ngModel>
    </p>
 
 
    <p>
      <label for="gender">Geneder </label>
      <input type="radio" value="male" id="gender" name="gender" ngModel> Male
      <input type="radio" value="female" id="gender" name="gender" ngModel> Female
    </p>
 
    <p>
      <label for="isMarried">Married </label>
      <input type="checkbox" id="isMarried" name="isMarried" ngModel>
    </p>
 
    <p>
      <label for="country">country </label>
      <select id="country" name="country" ngModel>
        <option [ngValue]="c.id" *ngFor="let c of countryList">
          {{c.name}}
        </option>
      </select>
    </p>
 
    <div ngModelGroup="address">
 
      <p>
        <label for="city">City</label>
        <input type="text" id="city" name="city" ngModel>
      </p>
 
      <p>
        <label for="street">Street</label>
        <input type="text" id="street" name="street" ngModel>
      </p>
      <p>
        <label for="pincode">Pin Code</label>
        <input type="text" id="pincode" name="pincode" ngModel>
      </p>
 
    </div>
 
    <p>
      <button type="submit">Submit</button>
    </p>
 
    <div>
      <button type="button" (click)="setDefault()">Default</button>
    </div>
    <div>
      <button type="button" (click)="setValue()">SetValue</button>
      <button type="button" (click)="setAddress()">Address</button>
      <button type="button" (click)="setCountry()">Country</button>
    </div>
    <div>
      <button type="button" (click)="patchName()">Name</button>
      <button type="button" (click)="patchAddress()">Address</button>
      <button type="button" (click)="reset()">Reset</button>
    </div>
 
 
  </form>
</div>
 
<div style="float: right; width:50%;">
  <h3>Form Status</h3>
  <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>

Conclusion

In this article, we learned how to set the values of Reactive forms in Angular using setValue and pathcValue.

I hope this article helps you and you will like it.👍

If you have any doubt or confusion then free to ask in comment section.

Post a Comment

Previous Post Next Post