Có hai cách để làm việc với form trong Angular, đó là template-driven và reactive. Hai cách này thực hiện khác nhau khi xử lý dữ liệu và sự kiện trong form. Mỗi cách có những thuận lợi riêng.
Chuẩn bị:
– Tạo project với lệnh
ng new suDungForm --defaults
– Mở src/index.html để chèn bootstrap
<!-- src/index.html -->
<link rel="stylesheet" href= "https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" >
1. Template-Driven Forms
Template-driven là phương pháp tạo form bằng cách nhập code html và directive angular trong view như thường làm.
a. Tạo component:
ng g c login
Hiện component trong app
//app.component.html
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { LoginComponent } from './login/login.component';
@Component({
selector: 'app-root', standalone: true,
imports: [RouterOutlet , LoginComponent],
templateUrl: './app.component.html',
styleUrl: './app.component.css'
})
export class AppComponent { title = 'Sử dụng form' }
<!-- app.component.html-->
<app-login></app-login>
b. Import FormsModule vào component
Component cần dùng form, cần import FormsModule vào .
//login.component.ts
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-login', standalone: true,
imports: [ FormsModule, CommonModule
],
templateUrl: './login.component.html',
styleUrl: './login.component.css'
})
export class LoginComponent { }
c. Tạo form với template driven trong angular
Code html tạo form như bình thường, trong đó khai báo biến ngform vào tag form và gắn ngModel vào từng control của form. Mỗi control trong form phải có biến name.
<!-- login.component.html -->
<!-- login.component.html -->
<form class="col-8 m-auto border border-2 border-info shadow-lg rounded p-3" #frm1="ngForm" >
<p> Username
<input name="username" ngModel class="form-control border-info shadow-none" type="text">
</p>
<p>Password
<input name="password" ngModel class="form-control border-info shadow-none" type="password">
</p>
<p><button type="submit" class="btn btn-info">Đăng nhập </button> </p>
<!-- hiện giá trị trong form
</form>
d. Lấy giá trị từ form
Bạn có thể truy xuất các giá trị mà user nhập trong form thông qua tên form đã định nghĩa và thuộc tính value của nó. Xem code sau:
<p> Value : {{frm1.value|json}} </p>
<p> Username : {{frm1.value.username}} </p>
<p> Password : {{frm1.value.password}} </p>
e. Sử dụng [(ngModel)] trong các control
iNếu không dùng ngModel, bạn có thể dùng [(ngModel)] để bind 2 chiều vào các biến trong component như sau
//login.component.ts
...
export class LoginComponent {
username:string='teonv';
password:string='123';
}
<!-- login.component.html -->
<form class="col-8 m-auto border border-2 border-info shadow-lg rounded p-3" #frm1="ngForm" >
<p> Username
<input name="un" [(ngModel)]="username" class="form-control border-info shadow-none" type="text">
</p>
<p>Password
<input name="pw" [(ngModel)]="password" class="form-control border-info shadow-none" type="password">
</p>
<p><button type="submit" class="btn btn-info">Đăng nhập</button> </p>
<p> Value : {{ frm1.value|json }} </p>
<p> Username : {{ frm1.value.un }} </p>
<p> Password : {{ frm1.value.pw }} </p>
</form>
Lấy giá trị từ form : Với cách dùng[(ngModel)] như trên thì các giá trị user nhập tự động đưa vào các biến tương ứng username. Các control cần có tham số name để có thể truy xuất giá trị trong view (xem hình dưới)
f. Kiểm tra dữ liệu trong form (validation)
Angular hỗ trợ kiểm tra dữ liệu trong form với các quy tắc dữ liệu nhập bạn chỉ ra. Ví dụ required, min, max, minlength, maxlength, type=email, type=date, type=number…
– Đầu tiên, bạn định nghĩa các quy tắc hợp lệ của dữ liệu trong control của form. Ví dụ sau là 2 quy tắc:
<input required minlength="6" name="un" [(ngModel)]="username" #loiun="ngModel" class="form-control border-info shadow-none" type="text">
– Sau đó định nghĩa biến kiểm lỗi trong control của form
<input required minlength="6" #loiun="ngModel" name="un" [(ngModel)]="username" class="form-control border-info shadow-none" type="text">
– Cuối cùng là hiện thông báo lỗi nếu user nhập sai quy tắc dữ liệu:
<p>Có lỗi: {{ loiun.invalid }} </p>
<p>Lỗi required: {{loiun.errors?.['required'] | json}} </p>
<p>Lỗi minlength: {{loiun.errors?.['minlength'] | json}} </p>
Bạn kết hợp *ngIf và các biến trạng thái lỗi để hiện các thông báo lỗi cho thân thiện hơn. Dùng invalid để hiện lỗi chung cho mọi quy tắc, hoặc dùng errors để hiện riêng từng lỗi cũng được. Xem ví dụ sau:
<p> Username
<input required minlength="6" #loiun="ngModel"
name="un" [(ngModel)]="username"
class="form-control border-info shadow-none" type="text">
<span class="text-danger" *ngIf="loiun.invalid">Nhập đúng nhé: </span>
<b class="text-primary" *ngIf="loiun.errors?.['required']">Chưa nhập username</b>
<b class="text-info" *ngIf="loiun.errors?.['minlength']">Nhập ít nhất 6 ký tự</b>
<em class="text-primary" *ngIf = "loiun.errors?.['minlength']['actualLength']<loiun.errors?.['minlength']['requiredLength']" >
Username chưa đủ dài
</em>
</p>
g. Định dạng các control trong form theo trạng thái
Angular tự động gán các class css của các form control theo trạng thái nhập liệu của user. Sau đây là các class được hỗ trợ: .ng-valid , .ng-invalid , .ng-pending , .ng-pristine, .ng-dirty, .ng-untouched, .ng-touched, .ng-submitted (enclosing form element only)
Việc angular tự động gán các class css như trên là rất hay. Bạn có thể tạo css trùng tên các class này để định dạng control theo các trạng thái của nó. Ví dụ tạo css định dạng các control mà user nhập không đúng quy tắc.
/* login.component.css */
input.ng-invalid { background-color: yellow;}
form.ng-invalid { background-color:antiquewhite;}
h. Xử lý submit
Để xử lý khi user submit form, bạn gọi 1 hàm trong component nhân sự kiện ngSubmit.
<form #frm1="ngForm" (ngSubmit)="xuly(frm1.value)" class = "col-8 m-auto border border-2 border-info shadow-lg rounded p-3" >
Và định nghĩa hàm xử lý trong component class:
export class LoginComponent {
username:string='teonv';
password:string='123';
xuly(d:any){
console.log("Data: ",d);
console.log("Username=", this.username);
console.log("Password=", this.password);
}
}
Khi gọi hàm xử lý, có thể truyền tham số cho hàm như ví dụ trên hoặc có thể dùng các biến trong class đã được bind từ form
2. Reactive Form trong Angular
Reactive form còn gọi là model driven form là cách tạo form thứ 2. Với cách này, đối tượng form và các thành phần được tạo bằng cách code trong file component.ts rồi bind ra view.
Các thành phần trong form reactive
- FormControl: tương ứng với 1 HTML form control như input, select, textarea…
- FormGroup : là một nhóm các đối tượng FormControl, FormGroup…
a. Tạo component
ng g c dangky
Nhúng component vào app
//app.component.html
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { DangkyComponent } from './dangky/dangky.component';
@Component({
selector: 'app-root', standalone: true,
imports: [RouterOutlet , DangkyComponent],
templateUrl: './app.component.html',
styleUrl: './app.component.css'
})
export class AppComponent { title = 'Sử dụng form' }
<!-- app.component.html-->
<<app-dangky></app-dangky>>
b. Import ReactiveModule trong component
Component nào muốn dùng Reactive thì import ReactiveModule , FormControl, FormGroup , CommonModule vào.
//dangky.component.ts
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormGroup, FormControl, ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-dangky', standalone: true,
imports: [ReactiveFormsModule, FormGroup, FormControl, CommonModule],
templateUrl: './dangky.component.html',
styleUrl: './dangky.component.css'
})
export class DangkyComponent { }
c. Template form reactive
Sau khi import ReactiveModule, bạn tạo template form. Template form reactive là form html bình thường, nhập trong view để tạo form như mong miốn.
<!-- dangky.component.html -->
<form class="col-8 m-auto border border-2 border-success shadow-lg rounded p-3" >
<p>Username
<input name="un" type="text"
class="form-control border-success shadow-none">
</p>
<p>Password
<input name="pw" type="password"
class="form-control border-success shadow-none" >
</p>
<p>Email
<input name="em" type="email"
class="form-control border-success shadow-none">
</p>
<p>
<button type="submit" class="btn btn-success px-4">Đăng ký</button>
</p>
</form>
d. Code tạo đối tượng form reactive
Sau khi có template, bạn itạo đối tượng FormGroup cho Form. Và tạo FormControl cho từng control trong form. Code trong hàm contructor hoặc ngOnInit của component.
//dangky.component.ts
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormGroup, FormControl, ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-dangky', standalone: true,
import { FormGroup, FormControl, ReactiveFormsModule , CommonModule } from '@angular/forms';
templateUrl: './dangky.component.html',
styleUrl: './dangky.component.css'
})
export class DangkyComponent {
frm1!: FormGroup;
ngOnInit(): void {
this.frm1 = new FormGroup({
username: new FormControl('yêulắm'),
password: new FormControl('lâmyếu'),
email: new FormControl('yeulắmlâmyếu@gmail.com'),
});
}
}
e. Binding control
Sau khi có template và đối tượng, bạn bind ra template trong tag form và các control như sau:
<!-- dangky.component.html -->
<form [formGroup]="frm1" class= "col-8 m-auto border border-2 border-success shadow-lg rounded p-3" >
<p> Username
<input formControlName="username" name="un"
class="form-control border-success shadow-none" type="text">
</p>
<p>Password
<input formControlName="password" name="pw"
class="form-control border-success shadow-none" type="password">
</p>
<p>Email
<input formControlName="email" name="em"
class="form-control border-success shadow-none" type="email">
</p>
<p>
<button type="submit" class="btn btn-success">Đăng ký</button>
</p>
</form>
f. Lấy giá trị trong form
Sử dụng cú pháp tênform.value. Ví dụ : frm1.value , sẽ lấy được các giá trị trong form.
<p>Form value {{frm1.value | json }}</p>
<p>Username: {{frm1.value.username}}</p>
</form>
g. Reactive form validator
Việc kiểm tra dữ liệu nhập trong các control của form thực hiện bằng cách thêm Validator vào form control. Thực hiện bằng cách thêm quiy tắc Validators trong tham số thứ 2 như dưới đây
//dangky.component.ts
import { Validators } from '@angular/forms';
...
export class DangkyComponent {
frm1!: FormGroup;
ngOnInit(): void {
this.frm1 = new FormGroup({
username: new FormControl('yêulắm', [Validators.minLength(6)]),
password: new FormControl('lâmyếu'
, [Validators.minLength(8), Validators.maxLength(20)] ),
email: new FormControl('yeulắmlâmyếu@gmail.com'),
});
}
}
Hiện các thông báo lỗi khi user nhập sai quy tắc:
<p> Username
<input formControlName="username" name="un"
class="form-control border-success shadow-none" type="text">
<em *ngIf="frm1.controls['username']?.errors" class="text-danger" >
Username dài ít nhất 6 ký tự nghe
</em>
</p>
<p>Password
<input formControlName="password" name="pw"
class="form-control border-success shadow-none" type="password">
<em *ngIf="frm1.controls['password']?.errors?.['minlength']['actualLength'] <
frm1.controls['password']?.errors?.['minlength']['requiredLength']" class="text-danger">
Mật khẩu còn ngắn lắm
</em>
</p>
Form Builder
Bạn cũng có thể tạo form trong code bằng chức năng FormBuilder rồi bind vào view:
a. Tạo component ng g c laptopThem
b. Nhúng component vào app
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { LaptopThemComponent } from './laptop-them/laptop-them.component';
@Component({
selector: 'app-root', standalone: true,
imports: [RouterOutlet , LaptopThemComponent],
templateUrl: './app.component.html',
styleUrl: './app.component.css'
})
export class AppComponent { title = 'Sử dụng form' }
<!-- app.component.html-->
<app-laptop-them></app-laptop-them>
c. Thực hiện form builder tạo các đối tượng cho form trong component.ts
//laptop-them.component.ts
import { Component, OnInit } from '@angular/core';
import { Form, FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
@Component({
selector: 'app-laptop-them',
templateUrl: './laptop-them.component.html',
styleUrls: ['./laptop-them.component.css']
})
export class LaptopThemComponent implements OnInit {
constructor(private fbuilder:FormBuilder) { }
frm1!:FormGroup;
ngOnInit(): void {
this.frm1 = this.fbuilder.group({
tenlt:['', Validators.required],
gialt: ['', [Validators.min(0), Validators.max(1000000000)]],
nhasx:['', Validators.min(1)],
status:['', Validators.required],
kmbalo:[true], kemoffile:[false], kmchuot:[true]
})
}
ngDoCheck(){ console.log(this.frm1);}
}
d. Code html tạo form và bind đối tượng vừa tạo với các tag trong form
<!-- laptop-them.component.html-->
<form [formGroup]="frm1" class="col-md-8 m-auto border-2 border border-success p-3 shadow-lg rounded">
<p> Tên Laptop
<input formControlName="tenlt" type="text" name="tenlt"
class="form-control border-success shadow-none">
</p>
<p> Giá Laptop
<input formControlName="gialt" type="number" name="gialt"
class="form-control border-success shadow-none">
</p>
<p>Tình trạng:
<input formControlName="status" type="radio" value="hangmoi">
Mới sản xuất
<input formControlName="status" type="radio" value="xairoi" >
Qua sử dụng
</p>
<p>Khuyến mãi:
<input type="checkbox" formControlName="kmbalo"> Balo
<input type="checkbox" formControlName="kemoffile"> Mua kèm Office
<input type="checkbox" formControlName="kmchuot"> Chuột Genius
</p>
<p> Nhà SX
<select formControlName="nhasx" name="nhasx"
class="form-control border-success shadow-none">
<option value="0">Chọn nhà sản xuát</option>
<option value="1">Dell</option>
<option value="2">HP</option>
</select>
</p>
<p> <button class="btn btn-success px-5">Thêm</button> </p>
</form>
Lấy dữ liệu user nhập trong form như bạn đã biết thôi, truy xuất các giá trị thông qua thuộc tính value của form. Xem ví dụ sau nhé:
<hr>
<p>{{frm1.value|json}}</p>
<p>{{frm1.value.tenlt}}</p>
<p>{{frm1.value.nhasx}}</p>
Để tham khảo thêm về làm việc với form trong Angular, mời các em tham khảo thêm tài liệu tại link này: https://angular.io/guide/forms , https://angular.io/guide/forms-overview, https://angular.io/guide/reactive-forms