Angular provides a robust framework for handling forms with both template-driven and reactive approaches. This guide will walk you through the key concepts and offer code examples for each.
1. Fundamental Concepts of Angular Forms
Angular forms enable the capture and validation of user input. They come in two flavors: Template-Driven and Reactive. Both approaches provide ways to bind user input to model data and validate that data.
2. Template-Driven Forms in Angular
Template-driven forms rely on Angular directives to create and manage forms within the HTML template.
HTML:
<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm)">
<div>
<label for="name">Name</label>
<input type="text" id="name" name="name" ngModel required>
</div>
<div>
<label for="email">Email</label>
<input type="email" id="email" name="email" ngModel required>
</div>
<button type="submit" [disabled]="myForm.invalid">Submit</button>
</form>
Component:
import { Component } from '@angular/core';
import { NgForm } from '@angular/forms';
@Component({
selector: 'app-template-driven-form',
templateUrl: './template-driven-form.component.html'
})
export class TemplateDrivenFormComponent {
onSubmit(form: NgForm) {
console.log('Form Data:', form.value);
}
}
3. Set Value in Template-Driven Forms
To programmatically set values in a template-driven form:
HTML:
<button type="button" (click)="setFormValue()">Set Form Value</button>
Component:
import { ViewChild, AfterViewInit } from '@angular/core';
@Component({
selector: 'app-template-driven-form',
templateUrl: './template-driven-form.component.html'
})
export class TemplateDrivenFormComponent implements AfterViewInit {
@ViewChild('myForm') form: NgForm;
ngAfterViewInit() {
// Ensure the form is available
}
setFormValue() {
if (this.form) {
this.form.setValue({
name: 'John Doe',
email: 'john.doe@example.com'
});
}
}
}
4. Reactive Forms in Angular
Reactive forms are more flexible and scalable, allowing the use of reactive programming techniques.
HTML:
<form [formGroup]="myForm" (ngSubmit)="onSubmit()">
<div>
<label for="name">Name</label>
<input id="name" formControlName="name">
</div>
<div>
<label for="email">Email</label>
<input id="email" formControlName="email">
</div>
<button type="submit" [disabled]="myForm.invalid">Submit</button>
</form>
Component:
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-reactive-form',
templateUrl: './reactive-form.component.html'
})
export class ReactiveFormComponent implements OnInit {
myForm: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.myForm = this.fb.group({
name: ['', Validators.required],
email: ['', [Validators.required, Validators.email]]
});
}
onSubmit() {
console.log('Form Data:', this.myForm.value);
}
}
5. FormBuilder in Reactive Forms
FormBuilder simplifies the creation of form controls.
Component:
constructor(private fb: FormBuilder) {
this.myForm = this.fb.group({
name: ['', Validators.required],
email: ['', [Validators.required, Validators.email]]
});
}
6. SetValue & PatchValue in Angular
setValue
sets the value for all controls, while patchValue
allows partial updates.
Component:
setFormValue() {
this.myForm.setValue({
name: 'John Doe',
email: 'john.doe@example.com'
});
}
patchFormValue() {
this.myForm.patchValue({
email: 'john.doe@example.com'
});
}
7. StatusChanges in Angular Forms
statusChanges
emits an event whenever the form's validation status changes.
Component:
ngOnInit() {
this.myForm.statusChanges.subscribe(status => {
console.log('Form Status:', status);
});
}
8. ValueChanges in Angular Forms
valueChanges
emits an event whenever the value of the form or any control changes.
Component:
ngOnInit() {
this.myForm.valueChanges.subscribe(value => {
console.log('Form Value:', value);
});
}
9. FormControl
FormControl
is used to create individual form controls.
Component:
const nameControl = new FormControl('John Doe', Validators.required);
10. FormGroup
FormGroup
aggregates multiple FormControl
instances into a single group.
Component:
this.myForm = new FormGroup({
name: new FormControl('John Doe', Validators.required),
email: new FormControl('john.doe@example.com', [Validators.required, Validators.email])
});
11. FormArray Example
FormArray
can manage an array of FormControl
, FormGroup
, or other FormArray
instances.
HTML:
<div formArrayName="emails">
<div *ngFor="let email of emails.controls; let i=index">
<label for="email{{i}}">Email {{i + 1}}</label>
<input [id]="'email' + i" [formControlName]="i">
</div>
</div>
<button type="button" (click)="addEmail()">Add Email</button>
Component:
get emails() {
return this.myForm.get('emails') as FormArray;
}
addEmail() {
this.emails.push(new FormControl('', [Validators.required, Validators.email]));
}
ngOnInit() {
this.myForm = this.fb.group({
name: ['', Validators.required],
email: ['', [Validators.required, Validators.email]],
emails: this.fb.array([this.fb.control('', [Validators.required, Validators.email])])
});
}
12. Build Dynamic or Nested Forms using FormArray
FormArray allows for dynamic forms, where users can add or remove controls as needed.
Component:
addEmail() {
this.emails.push(this.fb.control('', [Validators.required, Validators.email]));
}
13. SetValue & PatchValue in FormArray
setValue
and patchValue
can also be used with FormArray
.
Component:
setEmails() {
this.emails.setValue(['email1@example.com', 'email2@example.com']);
}
patchEmails() {
this.emails.patchValue(['email1@example.com']);
}
14. Select Options Dropdown
Dropdowns can be easily integrated with forms.
HTML:
<label for="selectedOption">Select Option</label>
<select id="selectedOption" formControlName="selectedOption">
<option *ngFor="let option of options" [value]="option">{{option}}</option>
</select>
Component:
options = ['Option 1', 'Option 2', 'Option 3'];
ngOnInit() {
this.myForm = this.fb.group({
selectedOption: ['', Validators.required]
});
}
15. Typed Forms in Angular
Typed forms improve type safety for form controls.
Component:
interface FormModel {
name: string;
email: string;
}
const form: FormGroup<FormModel> = new FormGroup({
name: new FormControl<string>(''),
email: new FormControl<string>('')
});
16. FormRecord in Angular
FormRecord
allows for dynamic control creation in form groups.
Component:
const record: FormRecord<FormControl<string>> = new FormRecord({
dynamicKey: new FormControl<string>('Initial Value')
});
record.addControl('newKey', new FormControl<string>('New Value'));
Conclusion
This guide covers the essential concepts of Angular forms, providing you with the knowledge to build both template-driven and reactive forms. By understanding these concepts and using the provided code examples, you can create robust, dynamic, and type-safe forms in your Angular applications.
Happy coding!
Exploring the Code
Visit the GitHub repository to explore the code in detail.