Daily Archives: 24/03/2017

Angular – Template – Phần 3

Trong phần này chúng ta sẽ tìm hiểu về biến template và 2 thuộc tính @Input@Output.

Biến template (#var)

Đây là các biến mà chúng ta khai báo cho mỗi element trong một trang web, chúng ta có thể dùng biến này để đọc dữ liệu và gọi phương thức của lớp component hoặc chỉ thị.

Để khai báo biến template thì chúng ta dùng kí tự # rồi ghi tên biến ngay bên trong element.

<input #phone placeholder="phone number">

Trong đoạn code trên chúng ta khai báo biến #phone cho element <input>. Sau khi đã khai báo thì chúng ta có thể gọi đến biến này ở bất cứ đâu trong đoạn code template đó.

<input #phone placeholder="phone number">

<button (click)="callPhone(phone.value)">Call</button>

Khi gọi biến template thì chúng ta ghi tên biến ra nhưng không ghi dấu #.

Trong đoạn code trên, khi chúng ta click button thì biến #phone sẽ lấy dữ liệu trong thuộc tính value của element <input>, rồi truyền vào phương thức callPhone().

Nếu chúng ta chỉ khai báo biến template không như thế thì thuộc tính value của biến hầu như sẽ là value của element, tuy nhiên chúng ta có thể chỉ định biến template này tham chiếu tới một đối tượng khác, chẳng hạn như một chỉ thị, ví dụ:

<form (ngSubmit)="onSubmit(customerorm)" #customerForm="ngForm">
    <div class="form-group">
        <label for="name">
            Name
            <input class="form-control" name="name" required [(ngModel)]="customer.name">
        </label>
    </div>
    <button type="submit" [disabled]="!customerForm.form.valid">Submit</button>
</form>

Nếu bạn còn nhớ thì mỗi khi chúng ta tạo form thì Angular sẽ gán cho form đó một đối tượng chỉ thị ngForm luôn để chúng ta có thể thực hiện một số thao tác trên form dễ dàng, chúng ta chỉ cần gán đối tượng ngForm đó cho biến template là có thể sử dụng được.

Chúng ta có thể sử dụng tiền tố ref- thay cho kí tự #, tùy bạn thích dùng cái nào cũng được.

<input ref-fax placeholder="fax number">
<button (click)="callFax(fax.value)">Fax</button>

Thuộc tính @Input và @Output

Hai thuộc tính này có tác dụng khai báo các biến và sự kiện dùng trong việc kết nối dữ liệu.

Trong các bài trước chúng ta đã quen với việc kết nối dữ liệu từ thuộc tính và sự kiện của element sang một thuộc tính hoặc phương thức của lớp component, ví dụ:

<img [src]="iconUrl"/>
<button (click)="onSave()">Save</button>

Trong đoạn code trên thì src là thuộc tính của element <img> và được kết nối tới thuộc tính iconUrl, click là sự kiện của element <button> và được kết nối tới phương thức onSave().

Điều này cũng có nghĩa là chúng ta chỉ được phép sử dụng các thuộc tính và sự kiện có sẵn của element như srcclick thôi, trong Angular có 2 thuộc tính @Input@Output, 2 thuộc tính này sẽ cho phép chúng ta tự tạo ra các thuộc tính và phương thức có thể bắt dữ liệu riêng cho chúng ta.

Ví dụ, chúng ta tạo một project mới và tạo một lớp tên CustomerFormComponent như sau:

import { Component, Input, Output, EventEmitter } from '@angular/core';
import { Customer } from './customer';

@Component({
    moduleId: module.id,
    selector: 'customer', 
    template: `<button type="button" class="btn btn-primary" (click)="emitEvent()">
                   Change name
               </button>
    ` 
})
export class CustomerFormComponent { 
    @Input() name: string;
    @Output() changeName = new EventEmitter(); 
 
    emitEvent() {
        this.changeName.emit();
    }
}

Chúng ta khai báo các thuộc tính @Input@Output bằng cách thêm 2 từ khóa này vào trước tên biến, sau đó khai báo kiểu dữ liệu đối với thuộc tính @Input hoặc gán một đối tượng EventEmitter cho thuộc tính @Output. Để có thể sử dụng @Input@Output thì chúng ta phải import từ @angular/core, ngoài ra ở đây chúng ta còn import thêm cả lớp EventEmitter nữa.

Lớp EventEmitter là lớp giúp phát sinh sự kiện, để phát sự kiện thì chúng ta gọi phương thức emit() của lớp này. Trong đoạn code trên lớp CustomerFormComponent có một template bao gồm 1 button, khi click button này thì phương thức emitEvent() sẽ được gọi, trong phương thức này chúng ta gọi phương thức emit() của đối tượng changeName để phát sinh sự kiện. Chi tiết về lớp EventEmitter sẽ được trình bày trong bài khác.

Tiếp theo chúng ta sử dụng lớp CustomerFormComponent như sau:

import { Component } from '@angular/core';
import { CustomerFormComponent } from './customer-form.component';

@Component({
    selector: 'my-app',
    template: ` 
        <customer [name]="username" (changeName)="saveNewName()"></customer> 
        {{username}}
    `,
})
export class AppComponent { 
    username = "Pho Code";
 
    saveNewName() {
        this.username = "Pho Code Blog";
    }
}

Chúng ta import lớp CustomerFormComponent, sau đó khai báo selector, rồi bắt các thuộc tính @Input@Output như bắt các thuộc tính và sự kiện thông thường.