Reactive forms in Angular provide a model-driven approach to handling form inputs whose values change over time. This approach is more powerful and flexible compared to template-driven forms, especially for complex forms. In this section, we will cover the basics of reactive forms, how to create and manage them, and how to handle form validation.
Key Concepts
- FormControl: Represents a single input field in a form.
- FormGroup: Represents a group of FormControls.
- FormBuilder: A service that helps to create FormGroups and FormControls.
- ReactiveFormsModule: The Angular module that needs to be imported to use reactive forms.
Setting Up Reactive Forms
Step 1: Import ReactiveFormsModule
First, you need to import ReactiveFormsModule
in your Angular module.
import { ReactiveFormsModule } from '@angular/forms'; @NgModule({ declarations: [ // your components ], imports: [ // other modules ReactiveFormsModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
Step 2: Create a Form in the Component
In your component, you will create a form using FormBuilder
.
import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; @Component({ selector: 'app-reactive-form', templateUrl: './reactive-form.component.html', styleUrls: ['./reactive-form.component.css'] }) export class ReactiveFormComponent implements OnInit { myForm: FormGroup; constructor(private fb: FormBuilder) { } ngOnInit(): void { this.myForm = this.fb.group({ name: ['', [Validators.required, Validators.minLength(3)]], email: ['', [Validators.required, Validators.email]], password: ['', [Validators.required, Validators.minLength(6)]] }); } onSubmit(): void { if (this.myForm.valid) { console.log(this.myForm.value); } } }
Step 3: Create the Template
In your component's HTML file, you will create the form template.
<form [formGroup]="myForm" (ngSubmit)="onSubmit()"> <div> <label for="name">Name:</label> <input id="name" formControlName="name"> <div *ngIf="myForm.get('name').invalid && myForm.get('name').touched"> <small *ngIf="myForm.get('name').errors.required">Name is required.</small> <small *ngIf="myForm.get('name').errors.minlength">Name must be at least 3 characters long.</small> </div> </div> <div> <label for="email">Email:</label> <input id="email" formControlName="email"> <div *ngIf="myForm.get('email').invalid && myForm.get('email').touched"> <small *ngIf="myForm.get('email').errors.required">Email is required.</small> <small *ngIf="myForm.get('email').errors.email">Invalid email format.</small> </div> </div> <div> <label for="password">Password:</label> <input id="password" type="password" formControlName="password"> <div *ngIf="myForm.get('password').invalid && myForm.get('password').touched"> <small *ngIf="myForm.get('password').errors.required">Password is required.</small> <small *ngIf="myForm.get('password').errors.minlength">Password must be at least 6 characters long.</small> </div> </div> <button type="submit" [disabled]="myForm.invalid">Submit</button> </form>
Practical Exercise
Task
Create a reactive form with the following fields:
- Username (required, minimum length 4)
- Email (required, valid email format)
- Age (required, must be a number between 18 and 65)
Solution
Component TypeScript File
import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; @Component({ selector: 'app-user-form', templateUrl: './user-form.component.html', styleUrls: ['./user-form.component.css'] }) export class UserFormComponent implements OnInit { userForm: FormGroup; constructor(private fb: FormBuilder) { } ngOnInit(): void { this.userForm = this.fb.group({ username: ['', [Validators.required, Validators.minLength(4)]], email: ['', [Validators.required, Validators.email]], age: ['', [Validators.required, Validators.min(18), Validators.max(65)]] }); } onSubmit(): void { if (this.userForm.valid) { console.log(this.userForm.value); } } }
Component HTML File
<form [formGroup]="userForm" (ngSubmit)="onSubmit()"> <div> <label for="username">Username:</label> <input id="username" formControlName="username"> <div *ngIf="userForm.get('username').invalid && userForm.get('username').touched"> <small *ngIf="userForm.get('username').errors.required">Username is required.</small> <small *ngIf="userForm.get('username').errors.minlength">Username must be at least 4 characters long.</small> </div> </div> <div> <label for="email">Email:</label> <input id="email" formControlName="email"> <div *ngIf="userForm.get('email').invalid && userForm.get('email').touched"> <small *ngIf="userForm.get('email').errors.required">Email is required.</small> <small *ngIf="userForm.get('email').errors.email">Invalid email format.</small> </div> </div> <div> <label for="age">Age:</label> <input id="age" type="number" formControlName="age"> <div *ngIf="userForm.get('age').invalid && userForm.get('age').touched"> <small *ngIf="userForm.get('age').errors.required">Age is required.</small> <small *ngIf="userForm.get('age').errors.min">Age must be at least 18.</small> <small *ngIf="userForm.get('age').errors.max">Age must be less than or equal to 65.</small> </div> </div> <button type="submit" [disabled]="userForm.invalid">Submit</button> </form>
Common Mistakes and Tips
- Not Importing ReactiveFormsModule: Ensure
ReactiveFormsModule
is imported in your Angular module. - Not Using FormBuilder: Using
FormBuilder
simplifies the creation of forms. - Improper Validation Handling: Always check for form control validity before accessing their values.
- Not Using FormGroup: Group related form controls using
FormGroup
for better organization and validation.
Conclusion
In this section, we covered the basics of reactive forms in Angular, including how to set up and manage them, and how to handle form validation. Reactive forms provide a powerful and flexible way to handle form inputs, especially for complex forms. In the next section, we will dive deeper into form validation and dynamic forms.
Angular 2+ Course
Module 1: Introduction to Angular
Module 2: TypeScript Basics
- Introduction to TypeScript
- TypeScript Variables and Data Types
- Functions and Arrow Functions
- Classes and Interfaces