How to Use FormControl in Angular

Angular FormControl is a built-in class used to get and set values and validate the form control fields like <input> or <select>. It tracks the value and validation status of an individual form control. It can be used standalone as well as with a parent form.

FormControl is one of the three fundamental building blocks of Angular forms, along with FormGroup and FormArray. It extends the AbstractControl class that implements most base functionality for accessing the value, validation status, user interactions, and events.

If you are confused with FormControl, FormGroup, FormArray, and Validators classes, this article will help you understand how they can work together to build excellent angular forms.

For every form control, such as text, checkbox, or radio button, we need to create an instance of FormControl in our class.

For example, we need to create an instance of the name field.

name = new FormControl();

In our HTML template, you can use the following code.

<input [formControl]="name">

Let’s take a basic example.

First, create a new angular project.

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

So, we imported the ReactiveFormsModule and added it to the imports array.

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, Validators } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  name = new FormControl('', [Validators.required]);
}

We have imported the FormControl and Validators class inside the app.component.ts file and created an instance of FormControl called name.

That means now we track the name field from the HTML form.

Write the following code inside an app.component.html file.

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

<div>
<input [formControl]="name">
<label *ngIf="name.invalid" [ngClass] = "'error'"> Name is required </label>
</div>

Also, we have a condition that says that if the name field is invalid, it will display the error.

If it is empty, it will show the error; if it is not, it will disappear.

Also, write the following code inside the app.component.css file.

.error{
  color: red;
  font-size: 15px;
}

Save the file and run the following command to start the angular dev server.

ng serve -o

You will see something like the following.

Angular form interface

When you start typing the name, the error will disappear.

Set the Default value in FormControl

We can set a default value to our form control, bypassing the value while instantiating a FormControl in our class. Update the following code inside the app.component.ts file.

// app.component.ts

name = new FormControl('The Weeknd', [Validators.required]);

Save the file, and you will see the textbox filled with “The Weeknd“.

Get value in FormControl.

We can get the value of a FormControl by using the value property on the instance of FormControl in our class. But first, update the following code inside the app.component.ts file.

// app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  name = new FormControl('The Weeknd', [Validators.required]);

  ngOnInit() {
    console.log(this.name.value);
  }
}

Save the file, and inside the console tab of the browser, you will see that The Weeknd is logged. 

So the value property fetches the value of the name FormControl.

Set value in FormControl

If a user has entered the new value in UI, our FormControl instance will be updated with the new value.

Now to set a value to a FormControl at run time, we need to call the setValue() method on the instance of FormControl in the class.

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

// app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  name = new FormControl('The Weeknd', [Validators.required]);
  setNameValue() {
    this.name.setValue('Ankit'); 
  } 
}

In this code, we have defined the setNameValue() function, which sets the value Ankit when the user fires an event like onchange or clicks an event on the button.

We are taking a button, so we must also update the app.component.html file.

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

<div>
  <input [formControl]="name">
  <label *ngIf="name.invalid" [ngClass] = "'error'"> Name is required </label>
  <div>
    <button (click)="setNameValue()">Set value</button>
  </div>
</div>

Save the file, and now, when you click on the Set value button, you will see the ‘Ankit’ inside the textbox.

FormControl with FormGroup using FormControlName

FormGroup tracks the value and validity state of a group of FormControl instances. FormGroup is one of the three fundamental building blocks used to define the forms in Angular, along with FormControl and FormArray.

The FormGroup aggregates the values of each child FormControl into one object, with each control name as a key. It calculates its status by reducing the status values of its children.

For example, if one of the controls in a group is invalid, the entire group becomes invalid. Therefore, when instantiating a FormGroup, pass in a collection of child controls as the first argument. The key for each child registers the name of the control.

Let’s add two more fields. Write the following code inside the app.component.ts file.

// app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  angForm = new FormGroup({
    name: new FormControl('Krunal', Validators.maxLength(10)),
    age: new FormControl(26, Validators.required),
    college: new FormControl('VVP College'),
  });
  
  onFormSubmit(): void {
    console.log('Name:' + this.angForm.get('name').value);
    console.log('Age:' + this.angForm.get('age').value);
    console.log('College:' + this.angForm.get('college').value);
  } 
}

First, we imported the FormGroup module from Angular forms, created an instance of FormGroup, passed all three fields, and created its FormControl instances.

The instance of FormControl created in the class has been used in HTML using angular formControlName that syncs the FormControl value with HTML form control.

The [formGroup] is the FormGroupDirective that binds the existing FormGroup to a DOM element.

When the form is submitted, we can access form values as follows.

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

So, when the user submits the form, we will get all three form field values inside the console log.

Angular FormControl Validation With FormGroup

Write the following code inside the app.component.html file.

// app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  angForm = new FormGroup({
    name: new FormControl('', Validators.required),
    age: new FormControl('', Validators.required),
    college: new FormControl('', Validators.required),
  });

  get name(): any {
    return this.angForm.get('name');
  }
  get age(): any {
    return this.angForm.get('age');
  }
  get college(): any {
    return this.angForm.get('college');
  } 
  
  onFormSubmit(): void {
    console.log('Name:' + this.angForm.get('name').value);
    console.log('Age:' + this.angForm.get('age').value);
    console.log('College:' + this.angForm.get('college').value);
  }
}

We need to get the value of that form control to validate a particular form control.

For example, to validate the name, age, and college FormControl, we must create a method in our class as above.

get name(): any {
    return this.angForm.get('name');
}
get age(): any {
    return this.angForm.get('age');
}
get college(): any {
    return this.angForm.get('college');
}

Write the following code inside the app.component.html file.

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

<form [formGroup] = "angForm" (ngSubmit)="onFormSubmit()">
  <input formControlName="name" />
  <label *ngIf="name.invalid" [ngClass] = "'error'"> Name is required. </label>
  
  <input formControlName="age" />
  <label *ngIf="age.invalid" [ngClass] = "'error'"> Age is required. </label>
  
  <input formControlName="college" />
  <label *ngIf="college.invalid" [ngClass] = "'error'"> College is required. </label>
  <div>
    <button type="submit">Send</button>
  </div>
</form>

In the *ngif condition, we can directly access that function name as an object name and call various properties on that object like invalid, valid, pending, pristine, dirty, untouched, or touched.

Save the file and go to the browser, and you will see something like this.

Angular FormControl Validation With FormGroup

FormControl with FormArray and FormControlName

In this section, we will use FormControl with FormArray and FormGroup using FormControlName.

In our angular application, FormArray dynamically generates form controls such as <input> and <select>.

Define names FormArray inside the app.component.ts file.

// app.component.ts

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

get names(): FormArray { 
    return this.angForm.get('names') as FormArray; 
 }

Next, we need to aggregate using FormGroup to name FormArray. Write the following code inside the app.component.ts file to do that.

// app.component.ts

angForm = new FormGroup({
    names: new FormArray([
      new FormControl('', Validators.required),
      new FormControl('', Validators.required),
    ])
});

In the above code, we have created an array of FormControl instances.

We will iterate it in our UI. Write the following code inside the app.component.html file. 

<div formArrayName="names">
  <div *ngFor="let name of names.controls; index as idx">
     <input [formControlName]="idx" placeholder="Enter a Name">
     <label *ngIf="name.invalid" [ngClass] = "'error'"> Name is required. </label>
  </div>
</div>

When we submit the form, we can fetch values as given below. 

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

// app.component.ts

onFormSubmit(): void {
    for(let i = 0; i < this.names.length; i++) {
      console.log(this.names.at(i).value);
    } 
  }

On the instance of FormArray, i.e., names, we will call controls that will return an array of FormControl instances.

To add a form control at run time, we need to use the push() method of FormArray.

We are also adding validation while creating FormControl instances.

// app.component.ts

addNameField() { 
    this.names.push(new FormControl('', Validators.required)); 
}

We can remove the form control at run time; we need to use the removeAt() method of FormArray.

// app.component.ts

deleteNameField(index: number) {
    this.names.removeAt(index);
}

So, our app.component.ts file looks like this.

// app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  angForm = new FormGroup({
    names: new FormArray([
      new FormControl('', Validators.required),
      new FormControl('', Validators.required),
    ])
  });
  
  get names(): FormArray { 
    return this.angForm.get('names') as FormArray; 
 }

  addNameField() { 
    this.names.push(new FormControl('', Validators.required)); 
  }
  
  deleteNameField(index: number) {
    this.names.removeAt(index);
  }

  onFormSubmit(): void {
    for(let i = 0; i < this.names.length; i++) {
      console.log(this.names.at(i).value);
    } 
  }
}

Now, write our final code inside the app.component.html file.

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

<form [formGroup] = "angForm" (ngSubmit)="onFormSubmit()">
  <div formArrayName="names">
    <div *ngFor="let name of names.controls; index as idx">
      <input [formControlName]="idx" placeholder="Enter a Name">
      <label *ngIf="name.invalid" [ngClass] = "'error'"> Name is required. </label>
      <button (click)="deleteNameField(idx)">Delete</button>
    </div>
  </div> 
  <div>
    <button type="submit">Send</button>
    <button type="button" (click)="addNameField()">Add More Names</button>
  </div>
</form>

Save the file, and you will see the following.

Angular FormControl Example

When you start typing your name at a particular textbox, for that specific textbox, the error will disappear.

We get all the dynamically added textbox values when the user submits the form.

That’s it!

Leave a Comment

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