When working with JavaScript frameworks, it’s best to avoid using clustered templates because the form logic lies in the component class. Reactive forms in Angular allow you to create clean forms without using too many directives. They also reduce the need for end-to-end testing since it’s very easy to validate your forms.
Put simply, form controls in Angular give the developer all the control, and nothing is implicit anymore — every choice about inputs and controls must be made intentionally and, of course, explicitly.
In this tutorial, we’ll show you how to divide form controls by form groups to create clusters that provide a platform to easily access the template element as groups. We’ll cover the following in detail:
FormControl
and FormGroup
in AngularFormControl
to a FormGroup
FormGroup
valueFormBuilder
in Angular?To illustrate the concept of form groups in Angular, we’ll walk through the process of building a reactive form so that you can fully grasp how to set it up with form groups.
To follow along, download the starter project on GitHub and open it in VS Code. If you haven’t already, you’ll want to update to the most recent version, Angular 11.
In Angular, form controls are classes that can hold both the data values and the validation information of any form element. Every form input you have in a reactive form should be bound by a form control. These are the basic units that make up reactive forms.
Form groups wrap a collection of form controls. Just as the control gives you access to the state of an element, the group gives the same access but to the state of the wrapped controls. Every single form control in the form group is identified by name when initializing.
FormControl
and FormGroup
in AngularFormControl
is a class in Angular that tracks the value and validation status of an individual form control. One of the three essential building blocks in Angular forms — along with FormGroup
and FormArray
— FormControl
extends the AbstractControl
class, which enables it to access the value, validation status, user interactions, and events.
FormGroup
is used with FormControl
to track the value and validate the state of form control. In practice, FormGroup
aggregates the values of each child FormControl
into a single object, using each control name as the key. It calculates its status by reducing the status values of its children so that if one control in a group is invalid, the entire group is rendered invalid.
The first step is to tell Angular that you want to use the form group by importing it inside the appropriate component.
To see how this works, navigate to the employee.component.ts
file and paste in the code block below:
import { Component, OnInit } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms' @Component({ selector: 'app-employee', templateUrl: './employee.component.html', styleUrls: ['./employee.component.css'] }) export class EmployeeComponent implements OnInit { bioSection = new FormGroup({ firstName: new FormControl(''), lastName: new FormControl(''), age: new FormControl('') }); constructor() { } ngOnInit() { } }
Here the form group was both imported and initialized to group together some form controls that compose the bio section of the form. To reflect this group, you have to associate the model to the view with the form group name, like this:
// copy inside the employee.component.html file <form [formGroup]="bioSection" (ngSubmit)="callingFunction()"> <label> First Name: <input type="text" formControlName="firstName"> </label> <label> Last Name: <input type="text" formControlName="lastName"> </label> <label> Age: <input type="text" formControlName="age"> </label> <button type="submit">Submit Application</button> </form>
Just like the form control, the form group name is used to identify the form group in the view, and on submit, the callingFunction
will be triggered.
Your app.component.html
file should look like this:
<div style="text-align:center"> <h2>Angular Job Board </h2> <app-employee></app-employee> </div>
Now run your application in development with the command:
ng serve
It should look like this:
The Angular reactive forms API makes it possible to nest a form group inside another form group.
Copy the code block below into the employee.component.ts
file:
import { Component, OnInit } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms' @Component({ selector: 'app-employee', templateUrl: './employee.component.html', styleUrls: ['./employee.component.css'] }) export class EmployeeComponent implements OnInit { bioSection = new FormGroup({ firstName: new FormControl(''), lastName: new FormControl(''), age: new FormControl(''), stackDetails: new FormGroup({ stack: new FormControl(''), experience: new FormControl('') }), address: new FormGroup({ country: new FormControl(''), city: new FormControl('') }) }); constructor() { } ngOnInit() { } callingFunction() { console.log(this.bioSection.value); } }
The main form group wrapper is the bio section, inside which both the stack details group and the address group is nested. As you can see, nested form groups are not defined by the assignment statement, but rather with the colon, just like a form control.
Reflecting this in the view will look like this:
// copy inside the employee.component.html file <form [formGroup]="bioSection" (ngSubmit)="callingFunction()"> <h3>Bio Details </h3> <label> First Name: <input type="text" formControlName="firstName"> </label> <br> <label> Last Name: <input type="text" formControlName="lastName"> </label> <br> <label> Age: <input type="text" formControlName="age"> </label> <div formGroupName="stackDetails"> <h3>Stack Details</h3> <label> Stack: <input type="text" formControlName="stack"> </label> <br> <label> Experience: <input type="text" formControlName="experience"> </label> </div> <div formGroupName="address"> <h3>Address</h3> <label> Country: <input type="text" formControlName="country"> </label> <br> <label> City: <input type="text" formControlName="city"> </label> </div> <button type="submit">Submit Application</button> </form>
It’s crucial that every name in the model and view match, so make sure you don’t misspell the form control names. When you save and run the application, if you do get any errors, read the error message and correct the misspelling you must have used.
You can style your component with the style instructions below:
input[type=text] { width: 30%; padding: 8px 14px; margin: 2px; box-sizing: border-box; } button { font-size: 12px; margin: 2px; padding: 8px 14px; }
If you run the application, you should see something like this in your browser:
When you use the form and submit, you will see your input results returned in the browser console. The complete code used in this tutorial is available on GitHub.
FormControl
to a FormGroup
To add, update, or remove controls in FormGroup
, use the following commands:
addControl()
adds a control and updates its value and validityremoveControl()
removes a controlsetControl()
replaces an existing controlcontains()
checks for enabled controls associated with a given nameregisterControl()
registers a control but, unlike the other methods, does not update its value and validityFormGroup
valueIn Angular, you can set values to individual form groups or set all FormGroup
values at once.
Use patchValue
to set only some values:
this.myFormGroup.patchValue({ formControlName1: myValue1, // formControlName2: myValue2 });
You do not need to supply all values here; fields whose values were not set will be unaffected.
To set all FormGroup
values simultaneously, use setValue
:
this.myFormGroup.setValue({ formControlName1: myValue1, formControlName2: myValue2 });
FormBuilder
in Angular?Setting up form controls can be tedious, especially if you’re working with very long forms. Angular’s FormBuilder
helps you streamline the process of building advanced forms while avoiding repetition.
Put simply, FormBuilder
provides syntactic sugar that eases the burden of creating instances of FormControl
, FormGroup
, or FormArray
and reduces the amount of boilerplate required to build complex forms.
For a deeper dive and examples on how to build complex forms, read our comprehensive Angular form builder tutorial.
In this tutorial, we covered everything you need to know about form controls in Angular, including how to use FormControl
, how to group form controls with FormGroup
, and why it’s critical to capture controls’ collective instances at once.
Debugging Angular applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Angular state and actions for all of your users in production, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording literally everything that happens on your site including network requests, JavaScript errors, and much more. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred.
The LogRocket NgRx plugin logs Angular state and actions to the LogRocket console, giving you context around what led to an error, and what state the application was in when an issue occurred.
Modernize how you debug your Angular apps — start monitoring for free.
ElectricSQL is a cool piece of software with immense potential. It gives developers the ability to build a true local-first application.
Leptos is an amazing Rust web frontend framework that makes it easier to build scalable, performant apps with beautiful, declarative UIs.
Learn more about the 5 best JavaScript libraries for dealing with multidimensional arrays, such as ndarray, math.js, and NumJs.
We spoke with Dom about his approach to balancing innovation with handling tech debt and to learn how he stays current with technology.
One Reply to "FormGroup and FormControl in Angular"
how to write error message for a control of nested form ?
*ngIf=”parentForm.controls.controlitem.errors”