Introduction:
Angular forms play a important role in creating dynamic and interactive web applications. Whether you're building a simple contact form or a complex multi-step wizard, Angular provides powerful features and tools to handle form validation, data binding, and user interactions. In this post, we will explore the everything we need to know about types of forms in angular and it's validations.
Table of Contents:
1. Angular Forms & Types
2. Template-Driven Forms
3. Reactive Forms
4. Advanced Form Handling Techniques
1. Angular Forms & Types
There are mainly two types of forms we need to know in angular,
i) Template-driven Forms
ii) Reactive Forms
Now let's see how to use this forms with example.
2. Template-Driven Forms
This is the type of form that uses ngModel
directive to keep track of input using two-way binding
.
The form which uses this kind of ngModel
mechanism is now called Template-Driven forms.
ngModel
and other form related directives are not available by default. So, before we start we need to explicitly import them into our application.
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { TemplateDrivenFormsComponent } from './template-driven-forms/template-driven-forms.component';
import { FormsModule } from '@angular/forms'; // <-- import from angular forms
@NgModule({
declarations: [AppComponent, TemplateDrivenFormsComponent],
imports: [BrowserModule, FormsModule], // <-- add it here
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
We've enable the Template Driven Forms
by adding FormsModule in to our application.
Our First Template-Driven form
<!-- template-driven-forms.component.html -->
<div>
<h1>Template-driven Form</h1>
<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm.value)">
<div>
<label>First Name:</label>
<input type="text" name="firstName [(ngModel)]="user.firstName" required>
</div>
<div>
<label>Last Name:</label>
<input type="text" name="lastName" [(ngModel)]="user.lastName" required>
</div>
<div>
<label>Password:</label>
<input type="password" name="password" [(ngModel)]="user.password" required>
</div>
<button type="submit" [disabled]="!myForm.valid">Submit</button>
</form>
</div>
// template-driven-forms.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-template-driven-forms',
templateUrl: './template-driven-forms.component.html',
styleUrls: ['./template-driven-forms.component.scss'],
})
export class TemplateDrivenFormsComponent implements OnInit {
user = {
firstName: 'foo',
lastName: 'bar',
password: 'foo@bar',
};
constructor() {}
ngOnInit(): void {}
onSubmit(user: typeof this.user) {
console.log(user);
}
}
ngForms
You can clearly see that we've created a reference for ngForm
template as myForm
. ngForm
can be only be created for HTML <form>
element.
This template is responsible for tracking all the of the form, which contains the value of form fields.
Also ngForm
keeps track of the validity state of the form, that depends on the validity state of each of it's form field.
ngSubmit
Next to (ngSubmit)
this event prevent the submission form to call backend HTTP POST request, like in the case of a plain HTTP form submit.
ngSubmit
directive will ensure that plain form submit not to occur instead it calls onSubmit(myForm.value)
function with the value of the form that can be accessed by the reference(myForm) we've created
CSS classes
Angular FormsModule provide css classes to apply style to the input based on the state of the input field.
ng-touched or ng-untouched
ng-valid or ng-invalid
ng-pristine or ng-dirty
These are the six classes provided by FormsModule for each form field in the form.
These validity states can be accessed by,
myForm.{nameOfField}.$touched
myForm.{nameOfField}.$valid
myForm.{nameOfField}.$dirty
// validity state of the form that we used to disable the button
myForm.valid
2. Reactive Forms
A reactive form is pretty much like template-driven form. But in order to achieve this we need to add another module called ReactiveFormsModule
.
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { TemplateDrivenFormsComponent } from './template-driven-forms/template-driven-forms.component';
import { ReactiveFormsModule } from '@angular/forms'; // <-- import from angular forms
@NgModule({
declarations: [AppComponent, TemplateDrivenFormsComponent],
imports: [BrowserModule, ReactiveFormsModule], // <-- add it here
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
Note that we've imported ReactiveFormsModule
instead of FormsModule
and that enables us to use reactive forms in our application.
Our First Reactive form
<!-- reactive-forms.component.html -->
<div>
<h1>Reactive Form</h1>
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<div>
<label>First Name:</label>
<input type="text" formControlName="firstName">
</div>
<div>
<label>Last Name:</label>
<input type="text" formControlName="firstName">
</div>
<div>
<label>Password:</label>
<input type="password" formControlName="password">
</div>
<button type="submit" [disabled]="!form.valid">Submit</button>
</form>
</div>
Note that we haven't used any references of form and we've removed the required
validation in and also there is no ngModel.
And That's the magic of reactive forms each and every control of the form is in our hands (i.e) we can control every state and value of each form fields in the TS file of this component.
FormGroup
FormGroup
is the main thing we need to know about Reactive Forms and it has the control of every form fields that contains.
// reactive-forms.component.ts
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-reactive-forms',
templateUrl: './reactive-forms.component.html',
styleUrls: ['./reactive-forms.component.scss'],
})
export class ReactiveFormsComponent implements OnInit {
form = new FormGroup({
firstName: new FormControl('', Validators.required),
lastName: new FormControl('', Validators.required),
password: new FormControl('', Validators.required),
});
constructor() {}
ngOnInit(): void {}
onSubmit() {
console.log('reactive form submitted');
console.log(this.form);
}
}
We can see that the form is really just a FormGroup, which keeps track of the global form value and the validity state.
Using this form group we can create simple form like this and also any kind of complex forms and even FormArray
FormGroup
contain multiple FormControl
and that is the name we've used inside HTML <input>
tag as formControlName
so that we can control that input tag.
This form have all the control over it's form fields like,
form.valid
form.invalid
form.control["firstName"].valid & .invalid
form.control["firstName"].touched & .untouched
form.control["firstName"].pristine
form.control["firstName"].enabled & .disabled
// or we can also get the fields using
form.get('firstName')
The same thing we've done in template-driven forms.
Also it has many features like,
-
reset()
the form. -
setValue('')
to any form fields. -
patchValue('')
to any form fields. -
setValue('')
to form and it need every value of form field. -
patchValue('')
to form and it doesn't need every value of form field. -
setError('')
to any form fields. - we can track each input change using
.valueChanges.subscribe((value) => {console.log(value)})
FromControl
It is used to create field inside the (FormGroup)[#group].
It contains the fields default value, disabled or enabled state and validation using Validators
new FormControl({value:"",disabled:false}, [Validators.required])
Validators
It is used to validate the form field in many ways like,
Validators.required
Validators.email
Validators.min
Validators.max
Validators.minLength
Validators.maxLength
Validators.pattern // we can create validation using regEx
These validations errors are accessed using the FormGroup
.
this.form.errors // will return all the errors in the form
this.form.controls["field-name"].errors // will return errors of particular field
There are many advanced techniques in Reactive forms like,
- Form Builder Api
- Form Array
- Error Handling Let's see these topics in the next post.
Happy Coding 💻 :).
Top comments (2)
Really helpful post. This would be very useful for my current project 😊
excellent explanation👏🏽