+1

Giới thiệu Form trong Angular 2

Như các bạn đã biết, trong bất kì application, web, web application thì Form là một thành phần không thể thiếu. Chính vì vậy, trong bài viết hôm nay thì mình và các bạn cùng nhau tìm hiểu về Form trong Angular 2 nhé !

Angular 2 hỗ trợ những loại Form nào, việc sử dụng các rule ra sao hay việc customize rule có khó không thì thông qua bài viết này hi vọng các bạn có thể hiểu phần nào về Form trong Angular 2

Angular 2 support phần Form linh hoạt hơn so với Angular 1, ta không bị giới hạn bởi việc chỉ dựa vào ngModel. Tùy vào mục đích sử dụng mà Angular 2 hỗ trợ 2 dạng sau đây:

  • Template-Driven Forms: sử dụng các directive được build sẵn để tạo nên các Form đơn giản, không phức tạp
  • FormBuilder: Sử dụng các API đã cung cấp sẵn để tạo những form phức tạp và handle được phần validation của Form

Trong bài viết này chúng ta cùng nhau tìm hiểu Form Builder nhé . Ok, let's go!

I. Giới thiệu cơ bản

1. Khai báo thư viện

  • Trước khi chúng ta sử dụng các Feature của Form thì ta cần khai báo các thư viện cần thiết để Angular biết và hỗ trợ các tính năng của các thư viện đó khi ta cần
  • Trong Module gốc ta cần import các thư viện sau: FormsModule, ReactiveFormsModule, Validators
  • Tiếp đó khai báo chúng vào phần import của file app.module
  • Demo:
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
import { ReactiveFormsModule, FormsModule, Validators } from '@angular/forms';
import { MyApp } from './components'

@ NgModule({
  imports: [
    BrowserModule,
    FormsModule,
    ReactiveFormsModule
  ],
  declarations: [MyApp],
  bootstrap: [MyApp]
})
export class MyAppModule {

}

platformBrowserDynamic().bootstrapModule(MyAppModule)

2. Input label

<label for="name">Name</label>
<input type="text" name="username" id="name">

Như các bạn thấy phần lớn Form HTML5 sử dụng label theo kiểu này. Nhưng, Angular 2 hoàn toàn có thể biến đoạn code HTML trên trở nên đơn giản hơn bằng cách lược bỏ phần label và thuộc tính id của Input trong HTML

  • Ví dụ:
<label>
  Name
  <input type="text" name="username">
</label>

II/ Tìm hiểu Form Builder

1. Form Builder Basic

  • Trước tiên, để dễ hiểu phần này thì các bạn chịu khó xem qua ví dụ dưới đây nhé:

  • Giả sử ta có file: app/login-form.component.ts và file app/login-form.component.html có nội dung như sau

  • File app/login-form.component.ts

import {Component} from '@angular/core';
import {
  FormBuilder,
  FormControl
} from '@angular/forms';

@Component({
  selector: 'login-form',
  templateUrl: 'app/login-form.component.html',
})

export class LoginForm {
  loginForm: FormGroup;
  username: FormControl;
  password: FormControl;

  constructor (builder: FormBuilder) {
    this.username = new FormControl('', []);
    this.password = new FormControl('', []);
    this.loginForm = builder.group({
      username: this.username,
      password: this.password
    });
  }

  login () {
    console.log(this.loginForm.value);
    // Attempt Logging in...
  }
}
  • File app/login-form.component.html
<form [formGroup]="loginForm" (ngSubmit)="login()">
  <label for="username">username</label>
  <input type="text" name="username" id="username" [formControl]="username">

  <label for="password">password</label>
  <input type="password" name="password" id="password" [formControl]="password">

  <button type="submit">log in</button>
</form>

(Link code demo: https://plnkr.co/edit/o1Gfqg?p=preview )

Qua ví dụ trên, mình xin giải thích một số điểm chính thế này:

class FormControl trong method constructor của class LoginForm này để làm gì:

  • Class này giúp chúng ta khởi tạo các giá trị ban đầu cho Form. Chính là ở param thứ nhất truyền vào. FormControl('inital_value', [])

  • Tạo các rules để validate form. Chính là ở param thứ 2. Param này được truyền vào dạng mảng nên các bạn có thể đưa nhiều rule vào. new FormControl('', ['', [Validators.required, Validators.maxLength(7)]])

  • Một điểm cần ghi nhớ nữa là method group của class FormBuilder phải được gán cho input có cùng tên(giống tên như khai báo)

  • Ví dụ: ở đây ta có thuộc tính username thì ngoài temlate chúng ta cũng cần một input có name là username. Angular2 quản lý việc này bằng việc sử dụng một method là formControlName. Ví dụ:

<div class="col-md-4">
<input formControlName="username" [(ngModel)]="user.username" class="form-control input-circle" size="16" type="text"/>
</div>
  • Điểm lưu ý tiếp theo là:

Nếu không có giá trị khởi tạo(giá trị mặc định) cho class FormControl thì chỉ cần truyền vào giá trị rỗng vào param đầu tiên, ví dụ: new FormControl('', [])

Tương tự với các rule cho phần validator, new FormControl('', [])

2. Tìm hiểu Validating FormBuilder

  • Qua ví dụ ở phần đầu tiên, chúng ta có thể hình dung được phần nào về khởi tạo rule, rule cơ bản trong Angular 2 rồi đúng không nào.

  • Ở phần này chúng ta tiếp tục tìm hiểu về một số rule trong Angular

  • Để hiểu hơn thì chúng ta tiếp tục đến với ví dụ tiếp theo nha(lol, đối với mình thì ví dụ là quan trọng nhất nên hơi nhiều ví dụ 😄)

  • Giả sử ta có các file sau:

File app/login-form.component.ts

import {
  // ...
  Validators
} from '@angular/forms';

@ Component({ /* ... */ })
export class LoginForm {
  loginForm: FormGroup;
  username: FormControl;
  password: FormControl;

  constructor (builder: FormBuilder) {
    this.username = new FormControl('', [
      Validators.required,
      Validators.minLength(5)
    ]);
    this.password = new FormControl('', [Validators.required]);
    this.loginForm = builder.group({
      username: this.username,
      password: this.password
    });
  }

  login () {
    console.log(this.loginForm.value);
    // Attempt Logging in...
  }
}

File app/login-form.component.html

<form [formGroup]="loginForm" (ngSubmit)="login()">
  Inside the form.
  <div>
    <label for="username">username</label>
    <input type="text" name="username" id="username" [formControl]="username">
    <div [hidden]="username.valid || username.untouched">
      <div>The following problems have been found with the username:</div>
      <div [hidden]="!username.hasError('minlength')">Username can not be shorter than 5 characters.</div>
      <div [hidden]="!username.hasError('required')">Username is required.</div>
    </div>
  </div>
  <div >
    <label for="password">password</label>
    <input type="password" name="password" id="password" [formControl]="password">
    <div [hidden]="password.valid || password.untouched">
      <div>The following problems have been found with the password:</div>
      <div [hidden]="!password.hasError('required')">The password is required.</div>
    </div>
  </div>
  <button type="submit" [disabled]="!loginForm.valid">Log In</button>
</form>

(Link code demo: https://plnkr.co/edit/kr8Q41?p=preview )

Qua ví dụ trên, ta có vài điểm cần hiểu như sau

  • Ở file đầu tiên app/login-form.component.ts thì không có gì khác biệt so với ví dụ ở phần trên(phần 1) nên mình không có gì giải thích thêm nha.

  • Ta sẽ làm việc với file thứ 2 app/login-form.component.html. Trong file này ta sử dụng 2 thuộc tính.valid.untouched để xác định xem nếu user có vi phạm rule chúng ta đã thiết lập thì sẽ hiển thị thông báo lỗi sẽ` ra cho người dùng thấy

  • Nếu có lỗi xảy ra thì làm sao hiển thị được chúng lên. À, Angular đã support cho chúng ta method hasError(). Vậy sử dụng nó ra sao?

  • À, việc sử dụng vô cùng đơn giản. Bạn chỉ cần truyền vào một string. String này là gì ? String này là tên Rule mà bạn muốn validate, thông thường là cùng tên với rule bạn đã định nghĩa trong component. Ví dụ:

<div [hidden]="!username.hasError('required')">Username is required.</div>

3. FormBuilder Custom Validation

  • Đôi khi các rule có sẵn mà thư viện Angular support sẽ không cover hết được các case trong thực tế nên yêu cầu đặt ra là: có thể tạo ra một rule của riêng mình được không. Câu trả lời là hoàn toàn được.

  • Chúng ta đến với ví dụ tiếp theo nhé

  • Giả sử chúng ta có file như sau:

File app/login-form.component.ts

function hasPunctuation (punctuation: string, errorType: string) {
  return function (input: FormControl) {
    return input.value.indexOf(punctuation) >= 0 ?
        null :
        { [errorType]: true };
  };
}

// ...

this.password = new FormControl('', [
  Validators.required,
  hasPunctuation('&', 'ampersandRequired')
]);
  • Giả sử chúng ta cần tạo ra một rule là hasPunctuation. Vậy làm sao chúng ta tạo ra rule như vậy ? Câu trả lời là: viết chúng thành một function trong Component. Rồi sử dụng chúng như một rule bình thường, giống như required hoặc minlength. Như ví dụ trên

  • Vậy khi viết rule rồi thì sử dụng rule đó để check như thế nào. Các bạn cứ gọi tên rule đã tạo vừa rồi và truyền các param vào cho nó trong class FormControl. Ví dụ:

<!-- ... -->
<div [hidden]="!password.hasError('ampersandRequired')">
  You must have an & in your password.
</div>
<!-- ... -->

(Link code demo: https://plnkr.co/edit/m5BpOX?p=preview )

4. Một số class Angular 2 support cho việc thông báo lỗi

  • Khi các bạn đã tạo ra các rule để validate cho form rồi thì việc hiển thị các thông báo lỗi cho người dùng biết cũng là một việc hết sức quan trọng. Hiểu được điều này nên Angular 2 đã support một số class để các bạn control được điều này thay vì phải viết những đoạn code css dài dòng. Vậy đó là các class nào, chúng ta cùng tìm hiểu nhé
/* field value is valid */
.ng-valid {}

/* field value is invalid */
.ng-invalid {}

/* field has not been clicked in, tapped on, or tabbed over */
.ng-untouched {}

/* field has been previously entered */
.ng-touched {}

/* field value is unchanged from the default value */
.ng-pristine {}

/* field value has been modified from the default */
.ng-dirty {}

Đến đây thì mình kết thúc bài viết. Cảm ơn các bạn đã chọn baì viết của mình để tham khảo. Hẹn gặp các bạn trong các chủ đề tiếp theo nha. Xin chào và hẹn gặp lại !


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí