Angular 14 FormGroup: The Complete Guide

Angular FormGroup tracks the value and validity state of a group of FormControl instances. ReactiveFormsModule enables FormGroup. FormGroup is used with FormControl and FormArray. The role of FormGroup is to track the value and validation state of the form control.

Angular 14 FormGroup

Angular FormGroup aggregates the values of each child FormControl into one object, with each control name as the key. FormGroup calculates its status by reducing the status values of its children. For instance, if one of the controls in the group is invalid, the entire group becomes invalid.

The FormGroup is one of the three fundamental building blocks used to define forms in Angular, along with FormControl and FormArray.

When instantiating the FormGroup, pass in the collection of child controls as a first argument. The key for each child registers the name for the control.

In this example, we will see how to instantiate Angular FormGroup and set and access values in FormGroup. We will also validate the form.

Let’s understand the angular form classes and directives we will use in our example.

FormControl:

FormControl is a class that tracks the value and validation state of a FormControl.

FormGroup:

FormGroup is a class that tracks the value and validity state of a group of FormControl.

FormArray: 

FormArray is a class that tracks the value and validity state of an array of FormControl, FormGroup, and FormArray.

FormControlName:

FormControlName is a directive that syncs a FormControl in an existing FormGroup to a form control by name.

FormGroupDirective:

FormGroupDirective is a directive that binds an existing FormGroup to a DOM element.

FormGroupName:

FormGroupName is a directive that syncs a nested FormGroup to a DOM element.

FormArrayName:

FormArrayName is a directive that syncs a nested FormArray to a DOM element.

Example

Let’s head back to practice and create a new Angular project.

As discussed earlier, we need to import the ReactiveFormsModule to work with FormGroup.

So, import the ReactiveFormsModule inside the app.module.ts file.

// app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ReactiveFormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

The next step is to write the following code inside the app.component.ts file.

// app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  mandoForm = new FormGroup({
    name: new FormControl(),
    series: new FormControl('The Mandalorian')
  });
  onFormSubmit(): void {
    console.log('Name:' + this.mandoForm.get('name').value);
    console.log('Series:' + this.mandoForm.get('series').value);
  }
}

We have imported the FormControl and Validators class inside the app.component.ts file and created an instance of FormGroup, consisting of FormControl instances name and series.

The onFormSubmit() function will be triggered when the user submits the form data. Write the following code into the app.component.html file.

<form [formGroup]="mandoForm" (ngSubmit)="onFormSubmit()">
  Name: <input formControlName="name"  placeholder="Enter Name">
  Series: <input formControlName="series"  placeholder="Enter Series">
  <button type="submit">Submit</button> 
</form>

Save the file and start the dev server of Angular using the following command.

ng serve -o

In the output, you can see two text boxes, one filled with values, and when you submit the form, you will see those textbox values logged in the browser’s console.

FormGroup setValue() and patchValue()

The setValue() and patchValue() are used to set values to FormGroup instance at run time.

The main difference between them is that when we use setValue(), we have to set all form controls in our FormGroup and when we use patchValue(), then selected form control can be set.

If we use setValue() and won’t set all the form controls in our FormGroup, it will throw an error. 

If we use patchValue(), there is no need to set all the form controls in our FormGroup.

Let’s understand by the following example.

Add the following code inside the app.component.ts file.

// app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  mandoForm = new FormGroup({
    name: new FormControl('Starwars'),
    series: new FormControl('C3PO')
  });
  onReset(): void {
    this.mandoForm.setValue({name: 'Padro Pascal', series: 'The Mandalorian' });
  }
  onPatch(): void {
    this.mandoForm.patchValue({ name: 'Padro Pascal' });
  }
  onFormSubmit(): void {
    console.log('Name:' + this.mandoForm.get('name').value);
    console.log('Series:' + this.mandoForm.get('series').value);
  }
}

In the above code, we have initialized mandoForm FormGroup with two form controls.

We then defined three functions to reset and patch the form control values.

Using setValue() in FormGroup

As I mentioned earlier, setValue() requires all the FormControl values, and if one is missing, it will throw an error like the following.

AppComponent.html:4 ERROR Error: Must supply a value for form control with name: ‘series’.
at forms.js:4504
at forms.js:4405
at Array.forEach (<anonymous>)
at FormGroup._forEachChild (forms.js:4401)
at FormGroup._checkAllValuesPresent (forms.js:4497)
at FormGroup.setValue (forms.js:4215)
at AppComponent.onReset (app.component.ts:15)
at Object.eval [as handleEvent] (AppComponent.html:4)
at handleEvent (core.js:34789)
at callWithDebugContext (core.js:36407)
View_AppComponent_0 @ AppComponent.html:4
proxyClass @ compiler.js:19257
logError @ core.js:36342
handleError @ core.js:7239
dispatchEvent @ core.js:22537
(anonymous) @ core.js:33721
(anonymous) @ platform-browser.js:1789
invokeTask @ zone-evergreen.js:391
onInvokeTask @ core.js:30885
invokeTask @ zone-evergreen.js:390
runTask @ zone-evergreen.js:168
invokeTask @ zone-evergreen.js:465
invokeTask @ zone-evergreen.js:1603
globalZoneAwareCallback @ zone-evergreen.js:1629
AppComponent.html:4 ERROR CONTEXT DebugContext_ {view: {…}, nodeIndex: 19, nodeDef: {…}, elDef: {…}, elView: {…}}

So, to avoid this error, we must pass all the form controls.

Using patchValue()

When we use patchValue(), it is unnecessary to mention all form controls.

onPatch(): void {
    this.mandoForm.patchValue({ name: 'Padro Pascal' });
}

We have not passed series form control. 

Now, write the following code inside the app.component.html file.

<!-- app.component.html -->

<form [formGroup]="mandoForm" (ngSubmit)="onFormSubmit()">
  Name: <input formControlName="name"  placeholder="Enter Name">
  Series: <input formControlName="series"  placeholder="Enter Series">
  <button (click) = "onReset()">Reset</button>
  <button (click) = "onPatch()">Patch</button>
  <button type="submit">Submit</button>
</form>

Now, you can reset or patch the form control values.

FormGroup Get Value

FormGroup is a collection of form controls. So, we can get the value of the form control name using the following method.

this.mandoForm.get('name').value

In the above example, we have already used this method inside the onFormSubmit() method.

onFormSubmit(): void {
    console.log('Name:' + this.mandoForm.get('name').value);
    console.log('Series:' + this.mandoForm.get('series').value);
}

FormGroup reset() in Angular.

We can reset the whole form by calling the reset() method on the FormGroup instance.

// app.component.ts

OnCompleteReset() {
    this.mandoForm.reset();
}

You can define your method and call the reset() method on the FormGroup instance. It will reset the values of the form. You need to call this method via a button click or other event.

If we want to reset the form with some default values, then assign the default values with the form control name.

// app.component.ts

OnCompleteReset() {
    this.mandoForm.reset({
      name: 'EdwardSnowden',
      series: 'CIA'
   });
  }

FormGroup valueChanges() and statusChanges()

We can track the value changes and status changes of a form control; we need to listen to them using the subscribe() method. See the below code.

// app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterViewInit {
  usrNameChanges: string;
  usrNameStatus: string;

  mandoForm = new FormGroup({
    name: new FormControl('Starwars'),
    series: new FormControl('C3PO')
  });
  ngAfterViewInit(): void {
    this.mandoForm.get('name').valueChanges.subscribe(data => this.usrNameChanges = data);
    this.mandoForm.get('name').statusChanges.subscribe(data => this.usrNameStatus = data);
  }
}

We have implemented AfterViewInit interface’s ngAfterViewInit() lifecycle method.

So, when the user changes the textbox’s value, the subscribe() method listens, and we can get the latest data of those text box values.

Inside the html view, we can check for those values, and if that name changes, we will display those values. For example, see the following code of the app.component.html file.

<!-- app.component.html -->

<form [formGroup]="mandoForm">
  Name: <input formControlName="name"  placeholder="Enter Name">
  Series: <input formControlName="series"  placeholder="Enter Series">
</form>
<p *ngIf="usrNameChanges">Name: <b>{{usrNameChanges}}</b> </p>
<p *ngIf="usrNameStatus">Name Status: <b>{{usrNameStatus}}</b> </p>

See the output.

Angular 8 FormGroup Example

Angular FormGroup Validation

We can validate the form control in FormGroup using the Validators class. We can use it to enable the validation in the form control, as given below.

// app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  mandoForm = new FormGroup({
    name: new FormControl('', Validators.required),
    series: new FormControl('', Validators.required)
  });

  get name(): any {
    return this.mandoForm.get('name');
  }
  onFormSubmit(): void {
    console.log('Name:' + this.mandoForm.get('name').value);
    console.log('Series:' + this.mandoForm.get('series').value);
  }
}

To check the validity of form control, we have written the following method for a form control as given below.

get name(): any {
    return this.mandoForm.get('name');
}

Now in the HTML template, we can access the validity state as userName.invalid. We can also get a validity state directly using an instance of FormGroup.

mandoForm.get('series').invalid

The final HTML code for validation is the following.

<form [formGroup]="mandoForm" (ngSubmit)="onFormSubmit()">
  <div>
	Name: <input formControlName="name"  placeholder="Enter Name">
	<label *ngIf="name.invalid" [ngClass] = "'error'"> Name is required with 10 max character. </label>
  </div>
  <div> 
	Series: <input formControlName="series"  placeholder="Enter Series">
	<label *ngIf="mandoForm.get('series').invalid" [ngClass] = "'error'"> Series is required. </label>
  </div>
  <div> 
       <button type="submit">Submit</button>
  </div>
</form>

See the output.

 

Angular 8 FormGroup Validation

Conclusion

In short, FormGroup is a collection of FormControls. It tracks the value of all the FormControl instances.

We have seen how to use FormGroup with FormControl, Validators, and different methods and properties in Angular.

That’s it for this tutorial.

Related posts

Angular Forms

Angular FormArray

Angular Form Validation

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.