Angular Forms – Template-driven and Reactive forms

Angular provides two main approaches for handling forms: template-driven forms and reactive forms. Let’s delve into each of these approaches in detail, along with examples for better understanding:

1. Template-Driven Forms:

Template-driven forms rely on Angular directives in the template to create and manage form controls. This approach is suitable for simpler forms with less complex validation requirements.

Example:

<!-- app.component.html -->
<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm)">
  <label for="name">Name:</label>
  <input type="text" id="name" name="name" ngModel required>

  <label for="email">Email:</label>
  <input type="email" id="email" name="email" ngModel required email>

  <button type="submit" [disabled]="!myForm.valid">Submit</button>
</form>

// app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent {
  onSubmit(form: any) {
    console.log('Form submitted:', form.value);
  }
}

In this example:

  • We use the ngForm directive to create a form and ngModel directive to bind form controls to properties in the component class.
  • We use template-driven validation attributes like required and email for basic validation.
  • We disable the submit button when the form is invalid using the [disabled] attribute binding.

2. Reactive Forms:

Reactive forms are model-driven forms that use an explicit form model to manage form controls and their validation. This approach is suitable for more complex forms and provides better control and flexibility over form validation and handling.

Example:

// app.component.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
  myForm: FormGroup;

  constructor(private fb: FormBuilder) {}

  ngOnInit() {
    this.myForm = this.fb.group({
      name: ['', [Validators.required]],
      email: ['', [Validators.required, Validators.email]]
    });
  }

  onSubmit() {
    if (this.myForm.valid) {
      console.log('Form submitted:', this.myForm.value);
    }
  }
}

<!-- app.component.html -->
<form [formGroup]="myForm" (ngSubmit)="onSubmit()">
  <label for="name">Name:</label>
  <input type="text" id="name" formControlName="name">

  <div *ngIf="myForm.controls.name.invalid && myForm.controls.name.touched">
    <div *ngIf="myForm.controls.name.errors.required">Name is required</div>
  </div>

  <label for="email">Email:</label>
  <input type="email" id="email" formControlName="email">

  <div *ngIf="myForm.controls.email.invalid && myForm.controls.email.touched">
    <div *ngIf="myForm.controls.email.errors.required">Email is required</div>
    <div *ngIf="myForm.controls.email.errors.email">Invalid email format</div>
  </div>

  <button type="submit" [disabled]="!myForm.valid">Submit</button>
</form>

In this example:

  • We use the FormBuilder service to create a form model with FormGroup and FormControl objects.
  • We define validators for each form control using Validators functions.
  • We bind the form model to the form element using [formGroup]="myForm" directive binding.
  • We handle validation messages and form control states using Angular template syntax and form control properties.

Both template-driven and reactive forms have their use cases, and the choice depends on the complexity of the form and the requirements of the application. Angular provides comprehensive support for both approaches, allowing developers to build robust and scalable forms for their applications.