Làm việc với form trong Angular

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.

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 trong view như thường làm.  

a. Nhúng FormsModule

Để tạo form theo cách này, bạn cần nhúng FormsModule vào project. Thực hiện bằng cách mở file app.modules.ts để khai báo :

import FormsModule trong Angular
import FormsModule vào app.module.ts đẻ tạo form với template-driven

Sau khi import module xong, Bạn tạo component để thực tập nhé: ng g c login

b. Tạo form với template driven trong angular

i. Code html tạo form như bình thường:

<!-- login.component.html -->
<form class="col-6 m-auto">
<p><label>Username</label> <input class="form-control" type="text"></p>
<p><label>Password</label> <input class="form-control" type="password"> 
</p>
<p><button class="btn btn-success">Đăng nhập</button> </p>
</form>

ii. Khai báo biến ngform và gắn ngModel trong các control của form

Sau khi code html cho form xong, bạn khai báo name cho form và name + ngModel cho các control trong form

<form #frm1="ngForm" class="col-6 m-auto">
<p><label>Username</label>
   <input name="username" ngModel class="form-control" type="text"> 
</p>
<p><label>Password</label>
   <input name="password" ngModel class="form-control" type="password"> 
</p>
<p><button type="submit" class="btn btn-success">Đăng nhập</button></p>
</form>

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>
Lấy giá trị từ form

ii. Nếu không dùng ngModel, bạn có thể dùng [(ngModel)] để bind vào các biến trong component như sau

<form #frm1="ngForm" class="col-6 m-auto">
<p><label>Username</label>
   <input name="un" [(ngModel)]="username" class="form-control" type="text"> 
</p>
<p><label>Password</label>
   <input name="pw" [(ngModel)]="password" class="form-control" type="password"> 
</p>
<p> <button class="btn btn-success">Đăng nhập</button> </p>
</form>
export class LoginComponent implements OnInit {
  constructor() { }
  ngOnInit(): void {}
  username:string='';
  password:string='';
}

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 biến đã định nghĩa

<p> Value : {{frm1.value|json}} </p>	
<p> Username : {{username}} </p>
<p> Password : {{password}} </p>
Lấy giá trị từ form

c. 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

<p> <label>Username</label>
<input [(ngModel)]="username" required minlength="6" class="form-control" name="username" type="text"> 
</p>

– Sau đó định nghĩa biến kiểm lỗi trong control của form

<p> <label>Username</label>
<input [(ngModel)]="username" required minlength="6" class="form-control" name="username" #loiun="ngModel" type="text"> 
</p>

– 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>loiun.invalid:  {{ loiun.invalid }} </p>
<p>loiun.errors.['required']: {{loiun.errors?.['required'] | json}} </p>
<p> loiun.errors?.['minlength']: {{loiun.errors?.['minlength'] | json}} </p>
Sữ dụng các biến vaidate trong form

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:

<em *ngIf="loiun.invalid" class="text-danger"> 
   Nhập username chưa đúng.  
</em>
<span *ngIf="loiun.errors?.['required']" class="text-danger"> 
   Username dài từ 6 ký tự nhé. 
</span>
<em *ngIf="loiun.errors?.['minlength']['actualLength']<loiun.errors?.['minlength']['requiredLength']" class="text-danger"> 
    Username chưa đủ dài 
</em>
Hiện báo lỗi user nhập trong form

d. Đị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)
Các class css status trong angular

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.

input.ng-invalid { background-color: yellow;}
form.ng-invalid { background-color:antiquewhite;}
Định dạng control theo css class của angular

e. Xử lý submit

Để xử lý khi user submit form, bạn gọi hàm nhân sự kiện ngSubmit.

<form #frm1="ngForm" (ngSubmit)="xuly(frm1.value)" class="col-6 m-auto">

Và định nghĩa hàm xử lý trong component class:

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.

Import module ReactiveFormsModule

Để có thể tạo form reactive trong Angular, bạn cần import module này vào. Thực hiện bằng cách mở file app.modules.ts để khai báo

import ReactiveFormsModule trong angular

Sau khi khai báo xong, trong ứng dụng bạn đã có thể tạo form reactive được rồi. Giờ thì bạn tạo form để thực tập nhé:

ng g c dangnhap

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, hay FormArray
  • FormArray : là một mảng các đối tượng

Template form reactive

Template cho form reactive là khối code html bình thường. Bạn bạn nhập trong view của component

<!-- dangnhap.component.html-->
<form class="col-6 m-auto" >
 <p><input type="text" name="u" class="form-control"> </p>
 <p><input type="password" name="u" class="form-control"></p>
 <p><button type="submit" class="btn btn-danger px-4 py-2"> Submit </button> </p>
</form>

Code tạo đối tượng form reactive

Sau khi có template, bạn code để tạo đối tượng form reactive trong hàm contructor hoặc ngOnInit của component. Xem code sau:

import { Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { FormGroup } from '@angular/forms';
@Component({
  selector: 'app-dangnhap',
  templateUrl: './dangnhap.component.html',
  styleUrls: ['./dangnhap.component.css']
})
export class DangnhapComponent implements OnInit {
  constructor() { }
  frm1!: FormGroup;
  ngOnInit(): void {
    this.frm1 = new FormGroup({
      username: new FormControl('teonv'),
      password: new FormControl('123'),
    });
  }
}

Binding control

Sau khi có template và đối tượng form, bạn bind ra template trong tag form và các control như sau:

<form class="col-6 m-auto" [formGroup]="frm1">
<p> <input formControlName="username" type="text" name="u" class="form-control"> </p>
<p> <input formControlName="password" type="password" name="u" class="form-control"></p>
<p><button type="submit" class="btn btn-danger px-4 py-2">Submit</button></p>
</form>
Tạo form theo cách Reactive trong Angular

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.

Lấy giá trị user nhập trong form

Reactive Forms 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 validate  trong tham số thứ 2 (xem hình dưới).

Code tạo form reactive trong component

Hiện các thông báo lỗi khi user nhập sai quy tắc:

<form class="col-6 m-auto" [formGroup]="frm1">
<p> 
  <input formControlName="username" type="text" name="u" class="form-control"> 
  <em *ngIf="frm1.controls['username']?.errors" class="text-danger" >
    Username từ 3 đến 10 ký tự nhe
  </em>
</p>
<p> 
  <input formControlName="password" type="password" name="u" class="form-control">
  <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:

//laptop-them.component.ts
import { Component, OnInit } from '@angular/core';
import { Form, FormBuilder, FormGroup, 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);}
}
<!-- laptop-them.component.html-->
<form [formGroup]="frm1" class="col-md-6 m-auto border border-success p-2">
<p> Tên Laptop 
    <input formControlName="tenlt" type="text" name="tenlt" class="form-control"> </p>
<p> Giá Laptop 
    <input formControlName="gialt" type="number" name="gialt" class="form-control"> </p>
<p>Tình trạng
    <input type="radio" value="hangmoi" formControlName="status">Mới sản xuất
    <input type="radio" value="xairoi" formControlName="status">Qua sử dụng
</p>
<p> Khuyến mãi
    <label><input type="checkbox" formControlName="kmbalo"> Balo </label> &nbsp; 
    <label><input type="checkbox" formControlName="kemoffile"> Mua kèm Office </label> &nbsp; 
    <label><input type="checkbox" formControlName="kmchuot"> Chuột Genius </label>
</p>
<p> Nhà SX
    <select formControlName="nhasx" name="nhasx" class="form-control">
        <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 p-2">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é:

<p>{{frm1.value|json}}</p>
<p>{{frm1.value.tenlt}}</p>
<p>{{frm1.value.nhasx}}</p>
Lấy giá trị user nhập trong form

Để 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-overview