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.
Top comments (1)
I think we could give piying-view a try. It inherits the core philosophy of ngx-formly and enhances it with more features, supporting directives, selectorless components, strong typing, and more. Additionally, it supports Angular's custom form controls without requiring any adaptation.