Reactive Form are types Angular Forms which works on model-driven approach to manage form data. Reactive Forms has Strong Data Model in form of FormControl object, which gives clear control and easy validation. Also we can create dynamic forms and update controls on runtime. Reactive form also easy to test.


Create Reactive Form

To create reactive form, first import ReactiveFormsModule in app.component.ts file. Also include FormControl ,FormGroup and FormArray classes in the component.

             /* app.component.ts */
import { Component, OnInit } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { ReactiveFormsModule } from '@angular/forms';
import { FormControl, FormArray, FormGroup } from '@angular/forms';

@Component({
    selector: 'app-root',
    standalone: true,
    imports: [RouterOutlet,FormsModule,CommonModule,ReactiveFormsModule],
    templateUrl: './app.component.html',
    styleUrl: './app.component.css'
  })
  export class AppComponent{
    title = 'myApp';
  }  
             /* app.component.html */

    <h1>{{title}}</h1>
    
    <form novalidate>
    
    <label>Email: <input type="email" name="email"></label>
    
    <label>Password: <input type="password" name="email" ></label>
    
    </form>
    

Form Control

FormControl class is added to one single form control to track its value and validity. We can create multiple FormControl for various input fields in form.

To view value of controls, use <output> with values.

             /* app.component.ts */
import { Component, OnInit } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { ReactiveFormsModule } from '@angular/forms';
import { FormControl, FormArray, FormGroup } from '@angular/forms';
    
@Component({
    selector: 'app-root',
    standalone: true,
    imports: [RouterOutlet,FormsModule,CommonModule,ReactiveFormsModule],
    templateUrl: './app.component.html',
    styleUrl: './app.component.css'
})
export class AppComponent{
    title = 'myApp';

    email=new FormControl('');
}  
             /* app.component.html */

<h1>{{title}}</h1>

<form novalidate>

<label>Email: <input type="email" name="email" [formControl]="email"></label>
<output>{{email.value}}</output>

</form>

Form Group

To use multiple form controls, use FormGroup class . FromGroup groups multiple FormControls and also track the validity and values of form or form controls group.

             /* app.component.ts */
import { Component, OnInit } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { ReactiveFormsModule } from '@angular/forms';
import { FormControl, FormArray, FormGroup } from '@angular/forms';
            
@Component({
    selector: 'app-root',
    standalone: true,
    imports: [RouterOutlet,FormsModule,CommonModule,ReactiveFormsModule],
    templateUrl: './app.component.html',
    styleUrl: './app.component.css'
})
export class AppComponent{
    title = 'myApp';
        
    loginform=new FormGroup({
        email:new FormControl(""),
        pass:new FormControl("")
    });

loginUser(){
    console.log(this.loginform.status);
    console.log(this.loginform.value);
    console.log(this.loginform.valid);
  };
}  
             /* app.component.html */
        
<h1>{{title}}</h1>
        
<form novalidate [formGroup]="loginform" (ngSubmit)="loginUser()">
        
<label>Email: <input type="email" name="email" formControlName="email"></label>
        
<label>Password: <input type="password" name="email"formControlName="pass"></label>

<button>Send</button>

<p>{{loginform.value | json}}</p>
<p>{{loginform.statue}}</p>
<p>{{loginform.valid}}</p>
        
</form>

Validator

To validate controls in Reactive Form, import class Validators in component. We can choose type of validation based on required, minlength or pattern.

For validation outputs, we can use hasError or invalid property in template.

Reactive Form Validation Example

             /* app.component.ts */
import { Component, OnInit } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { ReactiveFormsModule } from '@angular/forms';
import { Validators } from '@angular/forms';
import { FormControl, FormArray, FormGroup } from '@angular/forms';
              
@Component({
      selector: 'app-root',
      standalone: true,
      imports: [RouterOutlet,FormsModule,CommonModule,ReactiveFormsModule],
      templateUrl: './app.component.html',
      styleUrl: './app.component.css'
})

export class AppComponent{
    title = 'myApp';
          
    loginform=new FormGroup({
      email:new FormControl(null,[Validators.required, Validators.minLength(3)]),
      pass:new FormControl(null, [Validators.required, Validators.minLength(6)])
    });

    loginUser(){
      console.log(this.loginform.status);
      console.log(this.loginform.value);
      console.log(this.loginform.valid);
    };
}  
             /* app.component.html */
          
<h1>{{title}}</h1>
          
<form novalidate [formGroup]="loginform" (ngSubmit)="loginUser()">
          
<label>Email: <input type="email" name="email" formControlName="email">
<span *ngIf="loginform.get('email')?.hasError('required') && loginform.get('email')?.pristine"> Email Required</span>
<span *ngIf="loginform.get('email')?.invalid && loginform.get('email')?.dirty"> Email Invalid</span>
  </label>
          
<label>Password: <input type="password" name="email" formControlName="pass">
<span *ngIf="loginform.get('pass')?.invalid && loginform.get('pass')?.pristine"> Password Required</span> 
<span *ngIf="!loginform.get('pass')?.valid && loginform.get('pass')?.dirty"> Password Invalid</span> 
</label>
  
<button>Send</button>
  
<p>{{loginform.value | json}}</p>
<p>{{loginform.statue}}</p>
<p>{{loginform.valid}}</p>
          
</form>

FormBuilder

FormBuilder makes it easier to handle long forms with more inputs controls by simplifying syntax of FormControl and FormGroup.

To use FormBuilder, first import FormBuilder in component file. Now inject it to the component class as shown below.


import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { ReactiveFormsModule } from '@angular/forms';
import { FormBuilder } from '@angular/forms';
import { Validators } from '@angular/forms';
import { FormControl, FormArray, FormGroup } from '@angular/forms'; 

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet,FormsModule,CommonModule,ReactiveFormsModule],
  templateUrl: './app.component.html',
  styleUrl: './app.component.css'
})

export class AppComponent{
  title = 'myApp';
  
  constructor(private fb:FormBuilder){ }
  
  loginForm:FormGroup=this.fb.group({
      email:['',[Validators.required,Validators.minLength(4)]],
      pass:['',[Validators.required, Validators.minLength(6)]],
    });
  
}

<form novalidate [formGroup]="loginForm">
  <label>Email: <input type="email" name="email" required formControlName="email"></label>
  <label>Password: <input type="password" name="pass" required formControlName="pass"></label>
  <p> {{loginForm.value | json}}</p>
  <p>{{loginForm.valid}}</p>
</form>

update model using setValue and patchValue

setValue and patchValue is used to update the value of single form control or formGroup in reactive form.

setValue

setValue set new value of form controls or formGroup. use setValue when wen want to set Entire form controls.

patchValue

patchValue patch new values of individual or more form controls.


import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { ReactiveFormsModule } from '@angular/forms';
import { FormBuilder } from '@angular/forms';
import { Validators } from '@angular/forms';
import { FormControl, FormArray, FormGroup } from '@angular/forms'; 
      
@Component({
        selector: 'app-root',
        standalone: true,
        imports: [RouterOutlet,FormsModule,CommonModule,ReactiveFormsModule],
        templateUrl: './app.component.html',
        styleUrl: './app.component.css'
})
      
export class AppComponent{
  title = 'myApp';
        
  constructor(private fb:FormBuilder){ }
        
  loginForm:FormGroup=this.fb.group({
    email:['',[Validators.required,Validators.minLength(4)]],
    pass:['',[Validators.required, Validators.minLength(6)]],
  });

  setVal(){this.loginForm.setValue({email:"aa@bb",pass:'1234'})}
  patchVal(){this.loginForm.patchValue({email:"aa@bb"})}

}

<form novalidate [formGroup]="loginForm">
  <label>Email: <input type="email" name="email" required formControlName="email"></label>
  <label>Password: <input type="password" name="pass" required formControlName="pass"></label>

  <button (click)="setVal()"> Set </button>
  <button (click)="patchVal()"> Patch </button>
  <p> {{loginForm.value | json}}</p>
  <p>{{loginForm.valid}}</p>
</form>