Thursday, October 15, 2020

Angular Form setValue() and patchValue()

In this tutorial we’ll see how to set values for the form controls using setValue and patchValue in Angular forms. We’ll also see the difference between setValue and patchValue methods.


setValue in Angular

setValue as the name suggests is a method used to set values. You can use it to set value of a single form control instance, form group or form array.

For example if there is a FormControl named mail in your form and you want to set value for it

updateMail() {
  this.mail.setValue('abc@xyz.com');
}

One condition when using setValue method is that when used with form group or form array the value needs to match the structure of the group or array that is value needs to be set for all the control that form a group or array.

patchValue in Angular

Using patchValue you can update only a subset of properties defined in the FormGroup or FormArray object. It doesn’t force you to set values for all the controls that is the difference between setValue and patchValue methods.

You can use setValue and patchValue with both template-driven and reactive forms. So let’s start with a template-driven form.

setValue and patchValue in template-driven form

You can use setValue and patchValue with both template-driven and reactive forms. So let’s start with a template-driven form.

For the example we’ll take a form with fields name and email and a FromGroup that groups the controls for address (House No., City, State and Pin code).

Data Model

We’ll have separate Model classes also as Address and Member. In the Member class there will be a Address class reference.

address.model.ts

export class Address {
  houseNo: string;
  city: string;
  state: string;
  pinCode: string;
  constructor(houseNo: string, city: string, state: string, pinCode: string) {
    this.houseNo = houseNo;
    this.city = city;
    this.state  = state;
    this.pinCode = pinCode;
  }
}

member.model.ts

import { Address } from './address.model';

export class Member {
  name: string;
  mail: string;
  address: Address;
  constructor(name: string, mail: string, address: Address) {
    this.name = name;
    this.mail = mail;
    this.address = address;
  }
}

Template (app.component.html)

<div class="container">
  <div class="row">
    <div class="col-xs-12 col-sm-10 col-md-8">
      <h1>Membership Form</h1>
      <form (ngSubmit)="onSubmit()" #membershipForm="ngForm">
        <div class="row">
          <div class="col-xs-12 col-sm-10 col-md-6">
            <div class="form-group">
              <label for="name">Name</label>
              <input type="text" class="form-control" 
                id="name"
                ngModel name="name">                        
            </div>
          </div>
          <div class="col-xs-12 col-sm-10 col-md-6">
            <div class="form-group">
              <label for="email">email</label>
              <input type="email" class="form-control" 
                id="email"
                ngModel name="email">                        
            </div>
          </div>
        </div>
        <div ngModelGroup="addressgroup">
          <div class="row">
            <div class="col-xs-12 col-sm-10 col-md-6">
              <div class="form-group">
                <label for="houseNo">House No.</label>
                <input type="text" class="form-control" 
                id="houseNo"
                ngModel name="houseNo">
              </div>
            </div>
            <div class="col-xs-12 col-sm-10 col-md-6">
              <div class="form-group">
                <label for="city">City</label>
                <input type="text" class="form-control" 
                id="city"
                ngModel name="city">
              </div>
            </div>
          </div>
          <div class="row">
            <div class="col-xs-12 col-sm-10 col-md-6">
              <div class="form-group">
                <label for="state">State</label>
                <input type="text" class="form-control" 
                id="state"
                ngModel name="state">
              </div>
            </div>
            <div class="col-xs-12 col-sm-10 col-md-6">
              <div class="form-group">
                <label for="pin">Pin Code</label>
                <input type="text" class="form-control" 
                id="pin"
                ngModel name="pin">
              </div>
            </div>
          </div>
        </div>
        <button type="submit" class="btn btn-success">Submit</button>
        <button type="button" (click)="setDefault()" class="btn btn-primary ml-2">Set Defaults</button>
      </form> 
    </div>
  </div>
  <hr>
  <div *ngIf="submitted">
    <div class="row">
      <div class="col-xs-12 col-sm-10 col-md-8">
        <p>Name: {{member.name}}</p>
        <p>email: {{member.mail}}</p>
        <p>House Number: {{member.address.houseNo}}</p>
        <p>City: {{member.address.city}}</p>
        <p>State: {{member.address.state}}</p>
        <p>Pin Code: {{member.address.pinCode}}</p>
      </div>
    </div>
  </div>  
</div>

Important points to note here are-

  1. For the whole form a local reference “membershipForm” is created which is bound to the ngForm directive.
  2. ngModel is added with every element. This tells Angular that this element is a form control.
  3. The ngModelGroup directive is used to create a FormGroup which is a nested form group with in a form for grouping all the Address related form controls. Name given to the form group is "addressgroup".
    <div ngModelGroup="addressgroup">
    
  4. Apart from submit button there is also a “Set Defaults” button. That’s where we’ll use setValue and patchValue methods to set the default values for the controls.

Component class (app.component.ts)

import { Component, OnInit, ViewChild } from '@angular/core';
import { NgForm } from '@angular/forms';
import { Address } from './address.model';
import { Member } from './member.model';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent {
  address = new Address('', '', '', '');
  member = new Member('', '', this.address);
  submitted = false;
  @ViewChild('membershipForm') memberForm : NgForm;
  setDefault(){
    this.memberForm.setValue({
      name: 'Jay',
      email: 'jay@jay.co',
      addressgroup: {
        houseNo: '34, XYZ',
        city: 'Bat Cave',
        state: 'North Carolina',
        pin: '28710'
      }
    })
  }

  onSubmit(){
    this.submitted = true;
    this.member.name = this.memberForm.value.name;
    this.member.mail = this.memberForm.value.email;
    this.member.address.houseNo = this.memberForm.value.addressgroup.houseNo;
    this.member.address.city = this.memberForm.value.addressgroup.city;
    this.member.address.state = this.memberForm.value.addressgroup.state;
    this.member.address.pinCode = this.memberForm.value.addressgroup.pin;
  }
}

In the setDefault() method setValue method is used to set default values. In the template-driven form using the reference to the form you can use this method. As you can see all the form controls have to be used otherwise setValue won’t work.

setValue and patchValue Angular

Using patchValue

Drawback with setValue is that all the values have to be given that may not work for you because of the following reasons-

  • You don’t want to set all the values.
  • If there are already some values entered by the user every thing will be updated.

Alternative is using patchValue method where you can set values for some of the controls. For example if you want to set defaults for only city, state and pin then it can be done as-

setDefault(){
  this.memberForm.form.patchValue({
    addressgroup: {
      city: 'Bat Cave',
      state: 'North Carolina',
      pin: '28710'
    }
  })
}

Note that patchValue can’t be directly called using the form reference in template-driven form. You’ll have to call this method on the FormGroup instance which is wrapped inside the reference.

setValue and patchValue in Reactive form

We’ll use the same DataModel as used in the above example.

With Reactive form creation of FormGroup instance and form controls moves to Component class.

Component (app.component.ts)

import { Component, OnInit} from '@angular/core';
import { FormControl, FormGroup} from '@angular/forms';
import { Address } from './address.model';
import { Member } from './member.model';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html', 
})
export class AppComponent implements OnInit {
  address = new Address('', '', '', '');
  member = new Member('', '', this.address);
  submitted = false;
  membershipForm : FormGroup;
  ngOnInit() {
    this.membershipForm = new FormGroup({
      memberName: new FormControl(null),
      email: new FormControl(null),
      address: new FormGroup({
        houseNo: new FormControl(null),
        city: new FormControl(null),
        state: new FormControl(null),
        pinCode: new FormControl(null)
      })
    });
  }
  setDefault(){
    this.membershipForm.setValue({
      memberName: 'Jay',
      email: 'jay@jay.co',
      address: {
        houseNo: '34, XYZ',
        city: 'Bat Cave',
        state: 'North Carolina',
        pinCode: '28710'
      }
    })
  }
  onSubmit(){
    this.submitted = true;
    this.member.name = this.membershipForm.value.memberName;
    this.member.mail = this.membershipForm.value.email;
    this.member.address.houseNo = this.membershipForm.value.address.houseNo;
    this.member.address.city = this.membershipForm.value.address.city;
    this.member.address.state = this.membershipForm.value.address.state;
    this.member.address.pinCode = this.membershipForm.value.address.pinCode;
  }
}

Important points to note here are-

  1. Here we have a FormGroup named "membershipForm".
  2. With in that there is a neseted FormGroup named "address" to group all the address related controls.
  3. In the setDefault() method default values are set for all the controls using setValue() method. Since setValue() is used value needs to be set for all the control that form a group or array.

Template (app.component.html)

<div class="container">
  <div class="row">
    <div class="col-xs-12 col-sm-10 col-md-8">
      <h1>Membership Form</h1>
      <form [formGroup]="membershipForm" (ngSubmit)="onSubmit()">
        <div class="row">
          <div class="col-xs-12 col-sm-10 col-md-6">
            <div class="form-group">
              <label for="name">Name</label>
              <input type="text" class="form-control" id="name"
                    formControlName="memberName">                        
            </div>
          </div>
          <div class="col-xs-12 col-sm-10 col-md-6">
            <div class="form-group">
              <label for="email">email</label>
              <input type="email" class="form-control" id="email"
              formControlName="email">                        
            </div>
          </div>
        </div>
        <div formGroupName="address">
          <div class="row">
            <div class="col-xs-12 col-sm-10 col-md-6">
              <div class="form-group">
                <label for="houseNo">House No.</label>
                <input type="text" class="form-control" 
                id="houseNo" formControlName="houseNo">
              </div>
            </div>
            <div class="col-xs-12 col-sm-10 col-md-6">
              <div class="form-group">
                <label for="city">City</label>
                <input type="text" class="form-control" 
                id="city" formControlName="city">
              </div>
            </div>
          </div>
          <div class="row">
            <div class="col-xs-12 col-sm-10 col-md-6">
              <div class="form-group">
                <label for="state">State</label>
                <input type="text" class="form-control" 
                id="state" formControlName="state">
              </div>
            </div>
            <div class="col-xs-12 col-sm-10 col-md-6">
              <div class="form-group">
                <label for="pinCode">Pin Code</label>
                <input type="text" class="form-control" 
                id="pinCode" formControlName="pinCode">
              </div>
            </div>
          </div>
        </div>
        <button type="submit" class="btn btn-success">Submit</button>
        <button type="button" (click)="setDefault()" class="btn btn-primary ml-2">Set Defaults</button>
      </form> 
    </div>
  </div>
  <hr>
  <div *ngIf="submitted">
    <div class="row">
      <div class="col-xs-12 col-sm-10 col-md-8">
        <p>Name: {{member.name}}</p>
        <p>email: {{member.mail}}</p>
        <p>House Number: {{member.address.houseNo}}</p>
        <p>City: {{member.address.city}}</p>
        <p>State: {{member.address.state}}</p>
        <p>Pin Code: {{member.address.pinCode}}</p>
      </div>
    </div>
  </div>  
</div>

If you want to update values for some of the controls you can use patchValue method.

setDefault(){
  this.membershipForm.patchValue({
    address: {
      city: 'Bat Cave',
      state: 'North Carolina',
      pinCode: '28710'
    }
  })
}

That's all for this topic Angular Form setValue() and patchValue(). If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Angular Tutorial Page


Related Topics

  1. FormGroup in Angular With Examples
  2. Radio Button in Angular Form Example
  3. Checkbox in Angular Form Example
  4. Angular Reactive Form Validation Example
  5. Angular Custom Two-Way Data Binding

You may also like-

  1. Navigate to a Route Programmatically in Angular
  2. Highlight Currently Selected Menu Item Angular Routing Example
  3. Angular Cross Component Communication Using Subject Observable
  4. Angular ngIf Directive With Examples
  5. Reflection in Java - Getting Constructor Information
  6. BigDecimal in Java
  7. Python Program to Find Factorial of a Number
  8. Spring MVC XML Configuration Example With Annotations

No comments:

Post a Comment