Comparing Template-Driven Forms and Reactive Forms in Angular

Comparing Template-Driven Forms and Reactive Forms in Angular

Introduction

Angular provides two different approaches for handling forms: Template-Driven Forms and Reactive Forms. This tutorial will compare these two approaches, explain why Reactive Forms are often preferred, and demonstrate how to use native validators in Reactive Forms compared to Template-Driven Forms. Additionally, we'll provide practical examples of when to use each approach, such as in a CMS (Content Management System).

Template-Driven Forms

What are Template-Driven Forms?

Template-Driven Forms rely on Angular's directives to create forms directly in the template. They are straightforward and suitable for simple forms.

Example of Template-Driven Forms

Here's an example of a Template-Driven Form:

<form #form="ngForm">
  <label for="name">Name:</label>
  <input type="text" id="name" name="name" ngModel required>
  <div *ngIf="form.controls['name']?.invalid && form.controls['name']?.touched">
    Name is required.
  </div>
  <button type="submit" [disabled]="form.invalid">Submit</button>
</form>
        

Key Features of Template-Driven Forms

  • Simple syntax, ideal for basic forms.
  • Uses Angular directives like ngModel.
  • Less control over form validation and management.

When to Use Template-Driven Forms

Template-Driven Forms are suitable for:

  • Simple forms with minimal validation requirements.
  • Projects where quick prototyping is needed.
  • Smaller applications where form complexity is low.

Reactive Forms

What are Reactive Forms?

Reactive Forms, also known as Model-Driven Forms, provide more robust and scalable form handling. They are defined programmatically and offer better control over the form's state and validation.

Example of Reactive Forms

Here's an example of a Reactive Form:

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

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

  constructor(private fb: FormBuilder) {
    this.form = this.fb.group({
      name: ['', [Validators.required]]
    });
  }

  onSubmit() {
    if (this.form.valid) {
      console.log(this.form.value);
    }
  }
}
        
<!-- app.component.html -->
<form [formGroup]="form" (ngSubmit)="onSubmit()">
  <label for="name">Name:</label>
  <input id="name" formControlName="name">
  <div *ngIf="form.controls['name'].invalid && form.controls['name'].touched">
    Name is required.
  </div>
  <button type="submit" [disabled]="form.invalid">Submit</button>
</form>
        

Key Features of Reactive Forms

  • Defined programmatically using FormBuilder or FormGroup.
  • Offers better control and flexibility over form validation.
  • Ideal for complex forms and dynamic form handling.

Comparing Validators in Template-Driven and Reactive Forms

Template-Driven Validators

In Template-Driven Forms, validators are applied directly in the template using Angular directives. Validators such as required, minlength, maxlength, and pattern are commonly used.

<input type="text" id="name" name="name" ngModel required minlength="3">
<div *ngIf="form.controls['name']?.invalid && form.controls['name']?.touched">
  <div *ngIf="form.controls['name']?.errors?.['required']">Name is required.</div>
  <div *ngIf="form.controls['name']?.errors?.['minlength']">Name must be at least 3 characters long.</div>
</div>        

Reactive Form Validators

In Reactive Forms, validators are applied programmatically in the component class using functions provided by Angular.

this.form = this.fb.group({
  name: ['', [Validators.required, Validators.minLength(3)]]
});        
<form [formGroup]="form" (ngSubmit)="onSubmit()">

  <label for="name">Name:</label>

  <input id="name" formControlName="name">

  <div *ngIf="form.controls['name'].invalid && form.controls['name'].touched">

    <div *ngIf="form.controls['name'].errors?.['required']">Name is required.</div>

    <div *ngIf="form.controls['name'].errors?.['minlength']">Name must be at least 3 characters long.</div>

  </div>

  <button type="submit" [disabled]="form.invalid">Submit</button>

</form>        

Advantages of Reactive Forms

1. Scalability: Easier to manage complex forms.

2. Testability: Forms and their validation logic are easier to unit test.

3. Dynamic Forms: More straightforward to add/remove form controls dynamically.

4. Control: Provides fine-grained control over the form's state and validation.

Example of Using Native Validators

Template-Driven Forms

<form #form="ngForm">
  <label for="email">Email:</label>
  <input type="email" id="email" name="email" ngModel required email>
  <div *ngIf="form.controls['email']?.invalid && form.controls['email']?.touched">
    <div *ngIf="form.controls['email']?.errors?.['required']">Email is required.</div>
    <div *ngIf="form.controls['email']?.errors?.['email']">Invalid email format.</div>
  </div>

  <button type="submit" [disabled]="form.invalid">Submit</button>
</form>        

In this example:

  • The required validator ensures that the field is not empty.
  • The email validator ensures that the input is in the correct email format.
  • Error messages are conditionally displayed based on the form control's validity state.

Reactive Forms

Validators are defined programmatically using Angular's Validators class.

this.form = this.fb.group({
  email: ['', [Validators.required, Validators.email]]
});        
<form [formGroup]="form" (ngSubmit)="onSubmit()">
  <label for="email">Email:</label>
  <input id="email" formControlName="email">
  <div *ngIf="form.controls['email'].invalid && form.controls['email'].touched">
    <div *ngIf="form.controls['email'].errors?.['required']">Email is required.</div>
    <div *ngIf="form.controls['email'].errors?.['email']">Invalid email format.</div>
  </div>
  <button type="submit" [disabled]="form.invalid">Submit</button>
</form>        

In this example:

  • The Validators.required validator ensures that the field is not empty.
  • The Validators.email validator ensures that the input is in the correct email format.
  • Error messages are conditionally displayed based on the form control's validity state.


Why Choose Reactive Forms for a CMS?

In a Content Management System (CMS), forms are often complex and require dynamic validation rules based on user roles, content types, and other criteria. Reactive Forms are particularly suited for such scenarios due to:

  1. Dynamic Validation: Easily add or remove validators programmatically based on user interactions or content type changes.
  2. Complex Structures: Manage nested forms and dynamically generated form controls with ease.
  3. Better Control: Fine-grained control over the form’s state, allowing more sophisticated validation and error handling logic.


// cms-form.component.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-cms-form',
  templateUrl: './cms-form.component.html',
})
export class CmsFormComponent {
  form: FormGroup;

  constructor(private fb: FormBuilder) {
    this.form = this.fb.group({
      title: ['', [Validators.required]],
      content: ['', [Validators.required, Validators.minLength(10)]],
      author: ['', [Validators.required]],
      publishDate: ['', [Validators.required]]
    });
  }

  setAdvancedValidation() {
    if (this.form.controls['author'].value === 'admin') {
      this.form.controls['content'].setValidators([Validators.required, Validators.minLength(50)]);
    } else {
      this.form.controls['content'].setValidators([Validators.required, Validators.minLength(10)]);
    }
    this.form.controls['content'].updateValueAndValidity();
  }

  onSubmit() {
    if (this.form.valid) {
      console.log(this.form.value);
    }
  }
}        


<!-- cms-form.component.html -->
<form [formGroup]="form" (ngSubmit)="onSubmit()">
  <label for="title">Title:</label>
  <input id="title" formControlName="title">
  <div *ngIf="form.controls['title'].invalid && form.controls['title'].touched">
    <div *ngIf="form.controls['title'].errors?.['required']">Title is required.</div>
  </div>

  <label for="content">Content:</label>
  <textarea id="content" formControlName="content"></textarea>
  <div *ngIf="form.controls['content'].invalid && form.controls['content'].touched">
    <div *ngIf="form.controls['content'].errors?.['required']">Content is required.</div>
    <div *ngIf="form.controls['content'].errors?.['minlength']">Content must be at least {{ form.controls['content'].errors?.['minlength'].requiredLength }} characters long.</div>
  </div>

  <label for="author">Author:</label>
  <input id="author" formControlName="author" (blur)="setAdvancedValidation()">
  <div *ngIf="form.controls['author'].invalid && form.controls['author'].touched">
    <div *ngIf="form.controls['author'].errors?.['required']">Author is required.</div>
  </div>

  <label for="publishDate">Publish Date:</label>
  <input type="date" id="publishDate" formControlName="publishDate">
  <div *ngIf="form.controls['publishDate'].invalid && form.controls['publishDate'].touched">
    <div *ngIf="form.controls['publishDate'].errors?.['required']">Publish Date is required.</div>
  </div>

  <button type="submit" [disabled]="form.invalid">Submit</button>
</form>
        

Conclusion

Both Template-Driven and Reactive Forms have their use cases in Angular. Template-Driven Forms are suitable for simple forms and quick prototypes, while Reactive Forms offer better scalability, control, and testability for more complex applications. Reactive Forms are particularly advantageous in scenarios like a CMS where dynamic validation and complex form management are required. Understanding the differences and advantages can help you choose the right approach for your project's needs.

Anderson Cardoso Martins

Software Engineer | Full Stack Developer | Ruby On Rails | React | AWS

2 个月

Thanks for sharing Fernando Nunes!

回复
Douglas Baltazar

FullStack Developer | Java | Spring | Angular @ FATTO Consultoria e Sistemas

2 个月

Awesome content to read.

回复
Guilherme Lauxen Persici

Fullstack Software Engineer | PHP | Laravel | ReactJs | AWS | Docker

2 个月

Great article Fernando Nunes!

回复
Gerald Hamilton Wicks

Full Stack Engineer | React | Node | JavaScript | Typescript | Next | MERN Developer

2 个月

That's a great content Fernando Nunes ! One stuff that I miss from working with Angular are those form control, they are reeealy helpful !

回复

要查看或添加评论,请登录

社区洞察

其他会员也浏览了