Angular 17 provides powerful form-handling capabilities through Reactive Forms and Template-driven Forms. These two approaches offer different ways to build forms, depending on the complexity and requirements of the form.
1. Reactive Forms
Reactive forms are more explicit and synchronous; they allow for better control, validation, and state management.
Example: Creating a Reactive Form
- Step 1: Import
ReactiveFormsModulein your module
In your app module (app.module.ts), importReactiveFormsModule.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms'; // <-- Import this module
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, ReactiveFormsModule], // <-- Add it here
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
- Step 2: Create a Form in a Component
In your component, you’ll define a form usingFormBuilder,FormGroup, andFormControl.
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-reactive-form',
template: `
<form [formGroup]="userForm" (ngSubmit)="onSubmit()">
<label for="name">Name:</label>
<input id="name" formControlName="name">
<div *ngIf="userForm.get('name')?.invalid && userForm.get('name')?.touched">
Name is required.
</div>
<label for="email">Email:</label>
<input id="email" formControlName="email">
<div *ngIf="userForm.get('email')?.invalid && userForm.get('email')?.touched">
Please enter a valid email.
</div>
<button type="submit" [disabled]="userForm.invalid">Submit</button>
</form>
<pre>{{ userForm.value | json }}</pre>
`
})
export class ReactiveFormComponent {
userForm: FormGroup;
constructor(private fb: FormBuilder) {
this.userForm = this.fb.group({
name: ['', Validators.required],
email: ['', [Validators.required, Validators.email]],
});
}
onSubmit() {
if (this.userForm.valid) {
console.log('Form Submitted', this.userForm.value);
}
}
}
Explanation:
FormGroup: Represents the form as a whole.FormControl: Represents individual form controls (e.g., input fields).FormBuilder: A helper service to build form groups and form controls.- Validators are applied to form controls using the
Validatorsclass.
- Step 3: Using the Form in HTML
In the template, you bind the form to the component usingformGroup, and each control usesformControlName.
2. Template-Driven Forms
Template-driven forms are simpler to use, especially for small forms. Angular automatically tracks form states and values based on the DOM structure.
Example: Creating a Template-Driven Form
- Step 1: Import
FormsModulein your module
In your app module (app.module.ts), importFormsModule.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms'; // <-- Import this module
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, FormsModule], // <-- Add it here
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
- Step 2: Create a Form in a Component Template
In the template-driven approach, you define the form directly in the HTML template.
import { Component } from '@angular/core';
@Component({
selector: 'app-template-form',
template: `
<form #userForm="ngForm" (ngSubmit)="onSubmit(userForm)">
<label for="name">Name:</label>
<input id="name" name="name" ngModel required>
<div *ngIf="userForm.submitted && userForm.form.controls.name?.invalid">
Name is required.
</div>
<label for="email">Email:</label>
<input id="email" name="email" ngModel required email>
<div *ngIf="userForm.submitted && userForm.form.controls.email?.invalid">
Please enter a valid email.
</div>
<button type="submit" [disabled]="userForm.invalid">Submit</button>
</form>
<pre>{{ userForm.value | json }}</pre>
`
})
export class TemplateFormComponent {
onSubmit(form: any) {
if (form.valid) {
console.log('Form Submitted', form.value);
}
}
}
Explanation:
- Angular automatically registers form controls using the
ngModeldirective. - Form validation is done in the template using HTML attributes like
required,email, etc. #userForm="ngForm"creates a reference to the form in the template, andngFormtracks the form state.
- Step 3: Using the Form in HTML
Use thengModeldirective to bind the form controls to component data and track validation states.
3. Form Validation
Both reactive and template-driven forms support form validation. Validators are applied either declaratively in the template or imperatively in the component code.
Reactive Form Validation Example:
this.userForm = this.fb.group({
name: ['', [Validators.required, Validators.minLength(4)]],
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.required, Validators.pattern('(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,}')]],
});
Template-Driven Form Validation Example:
<input name="password" ngModel required minlength="8" pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}">
4. Form Array
In Reactive Forms, FormArray is used when you want to manage an array of form controls. It’s helpful when you need to dynamically add or remove form elements.
Example: Dynamic Form using FormArray
this.userForm = this.fb.group({
name: ['', Validators.required],
emails: this.fb.array([]),
});
get emails() {
return this.userForm.get('emails') as FormArray;
}
addEmail() {
this.emails.push(this.fb.control(''));
}
removeEmail(index: number) {
this.emails.removeAt(index);
}
Conclusion
Angular 17 continues to enhance form handling with both reactive and template-driven approaches. Here’s a summary:
- Reactive Forms: More flexible and scalable, better for complex forms.
- Template-driven Forms: Simpler and easier to use for small or medium-sized forms.
- Both approaches support validation and can be used based on the form’s complexity and requirements.
