Categories
Angular JavaScript

Angular Reactive Forms — Patching Values and Building Forms

Spread the love

Angular is a popular front-end framework made by Google. Like other popular front-end frameworks, it uses a component-based architecture to structure apps.

In this article, we’ll look at how to update values in the form group and use FormBuilder .

Patching the Model Value

There’re 2 ways to update the model value of Reactive forms.

We can either call setValue on an individual control to update the value or call patchValue on a FormGroup to replace values in the form model.

We can call setValue as follows:

app.component.ts :

import { Component } from "@angular/core";  
import { FormControl, FormGroup } from "@angular/forms";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"]  
})  
export class AppComponent {  
  personForm = new FormGroup({  
    name: new FormControl(""),  
    address: new FormGroup({  
      street: new FormControl("")  
    })  
  }); 

  updateName() {  
    this.personForm.setValue({ ...this.personForm.value, name: "Jane" });  
  }  
}

app.component.html :

<form [formGroup]="personForm">  
  <input type="text" formControlName="name" placeholder="Name" />  
  <div formGroupName="address">  
    <input type="text" formControlName="street" placeholder="Street" />  
  </div>  
</form><button (click)="updateName()">Update Name</button>

setValue strictly adheres to the structure of the form group, so we have to include everything as we did in the updateName method.

If we only want to update some values, we can use the patchValue method as follows:

app.component.ts :

import { Component } from "@angular/core";  
import { FormControl, FormGroup } from "@angular/forms";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"]  
})  
export class AppComponent {  
  personForm = new FormGroup({  
    name: new FormControl(""),  
    address: new FormGroup({  
      street: new FormControl("")  
    })  
  }); 

  updateName() {  
    this.personForm.patchValue({ name: "Jane" });  
  }  
}

app.component.html :

<form [formGroup]="personForm">  
  <input type="text" formControlName="name" placeholder="Name" />  
  <div formGroupName="address">  
    <input type="text" formControlName="street" placeholder="Street" />  
  </div>  
</form><button (click)="updateName()">Update Name</button>

In the code above, the updateName method changed to:

this.personForm.patchValue({ name: "Jane" });

As we can see, we don’t have to include all the fields. We only included the ones we want to update.

Generating Form Controls with FormBuilder

We can use the FormBuilder class to make creating Reactive forms easier for us.

To create a form with FormBuilder , we can write the following:

app.component.ts :

import { Component } from "@angular/core";  
import { FormBuilder } from "@angular/forms";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"]  
})  
export class AppComponent {  
  constructor(private fb: FormBuilder) {} 
  personForm = this.fb.group({  
    name: [""],  
    address: this.fb.group({  
      street: [""]  
    })  
  });  
}

app.component.html :

<form [formGroup]="personForm">  
  <input type="text" formControlName="name" placeholder="Name" />  
  <div formGroupName="address">  
    <input type="text" formControlName="street" placeholder="Street" />  
  </div>  
</form>

The code above has the same functionality as the other examples.

We have a personForm with the name field in the root form group and the street field nested in the address form group.

Simple Form Validation

To make sure what’s inputted if complete and correct, we have to add form validation to our form.

With Reactive forms, we can ads a single validator to our form control and also display the overall form status.

We can add validation as follows:

app.component.ts :

import { Component } from "@angular/core";  
import { FormBuilder, Validators } from "@angular/forms";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"]  
})  
export class AppComponent {  
  constructor(private fb: FormBuilder) {} 
  personForm = this.fb.group({  
    name: ["", Validators.required],  
    address: this.fb.group({  
      street: ["", Validators.required]  
    })  
  });  
}

app.component.html :

<form [formGroup]="personForm">  
  <input type="text" formControlName="name" placeholder="Name" required />  
  <div formGroupName="address">  
    <input type="text" formControlName="street" placeholder="Street" required />  
  </div>  
</form>

In the code above, we made the name and street fields required by importing the Validator and using the required property in each field.

Also, we have to add the required attribute in the inputs to prevent errors when the expression has changed after the template has been checked.

Displaying Form Status

We can reference the status property of our form to get the validator status of our form.

To do this, we just change app.component.html to the following:

<form [formGroup]="personForm">  
  <p>Form Status: {{ personForm.status }}</p>  
  <input type="text" formControlName="name" placeholder="Name" required />  
  <div formGroupName="address">  
    <input type="text" formControlName="street" placeholder="Street" required />  
  </div>  
</form>

Now the form should show the validation status of it. personForm.status returns 'INVALID' if it’s not valid and 'VALID' if it’s valid.

Therefore, we should see that in the first line of the form.

Dynamic Controls Using Form Arrays

To add dynamic controls, we can use the FormArray class.

We can use FormArray as follows:

app.component.ts :

import { Component } from "@angular/core";  
import { FormBuilder, FormArray } from "@angular/forms";

@Componen({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"]  
})  
export class AppComponent {  
  constructor(private fb: FormBuilder) {}  
  personForm = this.fb.group({  
    names: this.fb.array([this.fb.control("")])  
  }); 

  get names() {  
    return this.personForm.get("names") as FormArray;  
  } 

  addName() {  
    this.names.push(this.fb.control(""));  
  }  
}

app.component.html :

<form [formGroup]="personForm">  
  <div formArrayName="names">  
    <h3>Names</h3>  
    <button (click)="addName()">Add Name</button>  
    <div *ngFor="let n of names.controls; let i=index">  
      <label>  
        Name:  
        <input type="text" [formControlName]="i" />  
      </label>  
    </div>  
  </div>  
</form>

In the code above, we created the names form array in personForm .

Then in the template, we loop through the controls with the *ngFor in the form.

The formControlName is set to the index of the form control.

We also added an Add Name button to add a new form control.

Conclusion

We can use the FormBuilder class to save us time when we want to build forms.

It’s also useful for building dynamic forms since it takes FormArrays .

We can get the status of a form with the status property of the form group.

To update the values of the form, we can call the setValue or patchValue method of a form group.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *