Component và Template trong Angular

Component điều khiển một vùng màn hình được gọi là view. Ví dụ: các component riêng lẻ định nghĩa và kiểm soát từng view sau từ hướng dẫn Tour of Heroes:

  • Gốc của ứng dụng với các liên kết điều hướng.
  • Danh sách các anh hùng.
  • Cập nhật tên anh hùng.

Bạn xác định logic ứng dụng của một component — nó làm gì để hỗ trợ view — bên trong một lớp. Lớp tương tác với view thông qua một API gồm các thuộc tính và phương thức.

Ví dụ, component HeroListComponent có một thuộc tính heroes chứa danh sách các anh hùng. Phương thức selectHero() của nó gán giá trị cho thuộc tính selectedHero khi người dùng nhấp để chọn một anh hùng từ danh sách đó.

Component có được danh sách các anh hùng từ một dịch vụ, đó là parameter property của TypeScript trên phương thức khởi tạo. Dịch vụ được cung cấp cho component thông qua dependency injection.

export class HeroListComponent implements OnInit {
  heroes: Hero[] = [];
  selectedHero: Hero | undefined;

  constructor(private service: HeroService) { }

  ngOnInit() {
    this.heroes = this.service.getHeroes();
  }

  selectHero(hero: Hero) { this.selectedHero = hero; }
}

Angular tạo, cập nhật và hủy các component khi người dùng di chuyển qua ứng dụng. Ứng dụng của bạn có thể thực hiện hành động tại mỗi thời điểm trong vòng đời này thông qua các lifecycle hook tùy chọn, chẳng hạn như ngOnInit().

Siêu dữ liệu của Component

Decorator @Component xác định lớp ngay bên dưới nó như một lớp component và chỉ định siêu dữ liệu của nó. Trong đoạn mã ví dụ dưới đây, bạn có thể thấy rằng HeroListComponent chỉ là một lớp, không có ký hiệu Angular hoặc cú pháp đặc biệt nào cả. Nó không phải là một compon cho đến khi bạn đánh dấu nó bằng một decorator @Component.

Siêu dữ liệu của component cho Angular biết nơi lấy các khối xây dựng chính mà nó cần để tạo và trình bày component cũng như view của nó. Đặc biệt, nó liên kết một template với component, hoặc trực tiếp với mã nội tuyến hoặc bằng tham chiếu. Cùng với nhau, component và template của nó tạo thành view.

Ngoài việc chứa hoặc tham chiếu đến template, @Component còn cấu hình siêu dữ liệu, ví dụ: cách component có thể được tham chiếu trong HTML và những dịch vụ mà nó yêu cầu.

Đây là một ví dụ về siêu dữ liệu cơ bản cho component HeroListComponent.

@Component({
  selector:    'app-hero-list',
  templateUrl: './hero-list.component.html',
  providers:  [ HeroService ]
})
export class HeroListComponent implements OnInit {
/* . . . */
}

Ví dụ này cho thấy một số tùy chọn cấu hình hữu ích nhất của @Component:

  • selector: Một bộ chọn CSS yêu cầu Angular tạo và chèn một instance của component này vào bất cứ nơi nào nó tìm thấy thẻ tương ứng trong template HTML. Ví dụ: nếu HTML của ứng dụng có chứa <app-hero-list></app-hero-list>, thì Angular sẽ chèn một instance của HeroListComponent giữa các thẻ đó.
  • templateUrl: Địa chỉ của template HTML của component này. Ngoài ra, bạn có thể cung cấp template HTML nội tuyến, được gán vào giá trị của thuộc tính template. Template này định nghĩa host view của component.
  • providers: Một mảng các provider cho các service mà component yêu cầu. Trong ví dụ, điều này cho Angular biết cách cung cấp instance của service HeroService mà phương thức khởi tạo của component sử dụng để có được danh sách các anh hùng để hiển thị.

Template và View

Template và View trong Angular

Bạn tạo view của một component bằng template của nó. Template là một dạng HTML cho Angular biết cách hiển thị component.

View thường được sắp xếp phân cấp, cho phép bạn sửa đổi hoặc hiển thị và ẩn toàn bộ các phần hoặc trang giao diện người dùng như một đơn vị. Template ngay lập tức được liên kết với một component xác định host view của component đó. Component cũng có thể định nghĩa một cấu trúc view phân cấp, chứa các embbed view, được lưu trữ bởi các component khác.

Cấu trúc view phân cấp trong Angular

Hệ thống view phân cấp có thể bao gồm các view từ các component trong cùng một NgModule, nhưng nó cũng có thể (và thường xuyên) bao gồm các view từ các component được xác định trong các NgModule khác nhau.

Cú pháp của Template

Template trông giống như HTML thông thường, ngoại trừ việc nó cũng chứa cú pháp template Angular, cú pháp này thay đổi HTML dựa trên logic của ứng dụng của bạn và trạng thái của ứng dụng và dữ liệu DOM.

Template của bạn có thể sử dụng data binding để điều phối ứng dụng và dữ liệu DOM, pipe để chuyển đổi dữ liệu trước khi nó được hiển thị và directive để áp dụng logic ứng dụng cho những gì được hiển thị.

Ví dụ, đây là một template cho component HeroListComponent.

<h2>Hero List</h2>

<p><i>Select a hero from the list to see details.</i></p>
<ul>
  <li *ngFor="let hero of heroes" (click)="selectHero(hero)">
    {{hero.name}}
  </li>
</ul>

<app-hero-detail *ngIf="selectedHero" [hero]="selectedHero"></app-hero-detail>

Template này sử dụng các phần tử HTML điển hình như <h2><p>, và cũng bao gồm các phần tử của cú pháp template của Angular như: *ngFor, {{hero.name}}, (click), [hero]<app-hero-detail>. Các phần tử cú pháp template cho Angular biết cách hiển thị HTML ra màn hình, sử dụng dữ liệu và logic của chương trình.

  • *ngFor: Lệnh yêu cầu Angular lặp qua một danh sách.
  • {{hero.name}}, (click)[hero] liên kết dữ liệu chương trình tới và từ DOM, phản hồi với đầu vào của người dùng. Xem thêm về data binding ở bên dưới.
  • Các thẻ <app-hero-detail> trong ví dụ này là một phần tử đại diện cho một component mới, là HeroDetailComponent. HeroDetailComponent (mã không được hiển thị ở đây) định nghĩa view con thông tin chi tiết của anh hùng - HeroListComponent. Lưu ý cách các component tùy chỉnh như thế này kết hợp liền mạch với HTML gốc trong cùng một bố cục.

Data binding

Nếu không có framework, bạn sẽ chịu trách nhiệm đẩy các giá trị dữ liệu vào các điều khiển HTML và biến phản hồi của người dùng thành hành động và cập nhật giá trị.

Viết logic đẩy và kéo như vậy bằng tay thật tẻ nhạt, dễ xảy ra lỗi và là một cơn ác mộng khi đọc, như bất kỳ lập trình viên JavaScript front-end có kinh nghiệm nào cũng có thể chứng thực.

Angular hỗ trợ data binding hai chiều, một cơ chế để phối hợp các phần của một framework với các phần của một component. Thêm binding markup vào template HTML để cho Angular biết cách kết nối cả hai bên.

Sơ đồ sau đây cho thấy bốn hình thức đánh dấu liên kết dữ liệu. Mỗi biểu mẫu có một hướng: tới DOM, từ DOM hoặc cả hai.

Các loại data binding trong Angular

Ví dụ: template của HeroListComponent này sử dụng ba trong số các biểu mẫu này.

<li>{{hero.name}}</li>
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
<li (click)="selectHero(hero)"></li>
  • Interpolation {{hero.name}} hiển thị giá trị thuộc tính hero.name của component trong phần tử <li>.
  • Property binding [hero] truyền giá trị của selectedHero từ component cha HeroListComponent đến thuộc tính hero của component con HeroDetailComponent.
  • Event binding (click) gọi phương thức selectHero của component khi người dùng nhấp vào tên của anh hùng.

Data binding hai chiều (được sử dụng chủ yếu trong các biểu mẫu hướng template) kết hợp property bindingevent binding trong một ký hiệu duy nhất. Đây là một ví dụ từ template của HeroDetailComponent sử dụng data binding hai chiều với directive ngModel.

<input type="text" id="hero-name" [(ngModel)]="hero.name">

Trong data binding hai chiều, một giá trị thuộc tính dữ liệu truyền đến control input từ component bằng property binding. Các thay đổi của người dùng cũng được truyền ngược trở lại component, gán giá trị mới nhất cho thuộc tính, tương tự như event binding.

Angular xử lý tất cả data binding một lần cho mỗi chu kỳ sự kiện JavaScript, từ gốc của cây component ứng dụng thông qua tất cả các component con.

Data binding giữa template và component trong Angular

Data binding đóng một vai trò quan trọng trong giao tiếp giữa một framework và component của nó, và cũng quan trọng đối với giao tiếp giữa các component cha và component con.

Data binding giữa component cha và component con trong Angular

Pipe

Pipe trong Angular cho phép bạn khai báo các phép biến đổi giá trị hiển thị trong template HTML của bạn. Một lớp với decorator @Pipe định nghĩa một hàm chuyển đổi các giá trị đầu vào thành giá trị đầu ra để hiển thị trong một view.

Angular định nghĩa một số pipe khác nhau, chẳng hạn như pipe date và pipe currency; để có danh sách đầy đủ, hãy xem danh sách Pipe API. Bạn cũng có thể tự định nghĩa pipe mới.

Để chỉ định một phép chuyển đổi giá trị trong template HTML, hãy sử dụng toán tử pipe (|).

{{interpolated_value | pipe_name}}

Bạn có thể xâu chuỗi các pipe, gửi đầu ra của một pipe này vào một pipe khác. Một pipe cũng có thể nhận các đối số kiểm soát cách nó thực hiện chuyển đổi. Ví dụ: bạn có thể chuyển định dạng mong muốn vào pipe date.

<!-- Default format: output 'Jun 15, 2015'-->
 <p>Today is {{today | date}}</p>

<!-- fullDate format: output 'Monday, June 15, 2015'-->
<p>The date is {{today | date:'fullDate'}}</p>

 <!-- shortTime format: output '9:43 AM'-->
 <p>The time is {{today | date:'shortTime'}}</p>

Directive

Directive trong Angular

Các template trong Angular là dynamic. Khi Angular hiển thị chúng, nó sẽ biến đổi DOM theo các hướng dẫn được đưa ra bởi các directive. Directive là một lớp có decorator @Directive().

Về mặt kỹ thuật, một component là một directive. Tuy nhiên, các component rất đặc biệt và là trung tâm của các ứng dụng Angular đến mức Angular định nghĩa decorator @Component(), bổ sung decorator @Directive() với các tính năng hướng template.

Ngoài các component, có hai loại directive khác: structural directiveattribute directive. Angular định nghĩa một số directive của cả hai loại và bạn có thể định nghĩa directive của riêng mình bằng cách sử dụng decorator @Directive().

Cũng như đối với các component, siêu dữ liệu cho một directive liên kết lớp có decorator với một phần tử selector mà bạn sử dụng để chèn nó vào HTML. Trong các template, các directive thường xuất hiện trong thẻ phần tử dưới dạng các thuộc tính, theo tên hoặc là mục tiêu của một phép gán hoặc một binding.

Structural directive

Structural directive thay đổi bố cục bằng cách thêm, xóa và thay thế các phần tử trong DOM. Template ở ví dụ dưới đây sử dụng hai structural directive tích hợp để thêm logic ứng dụng vào cách hiển thị view.

<li *ngFor="let hero of heroes"></li>
<app-hero-detail *ngIf="selectedHero"></app-hero-detail>
  • *ngFor là một directive vòng lặp; nó yêu cầu Angular tạo thẻ <li> cho mỗi anh hùng trong danh sách heroes.
  • *ngIf là một directive điều kiện; nó chỉ bao gồm component HeroDetail nếu tồn tại một anh hùng được chọn.

Attribute directive

Attribute directive thay đổi hình thức hoặc hành vi của một phần tử hiện có. Trong các template, chúng trông giống như các thuộc tính HTML thông thường.

Directive ngModel thực hiện data binding hai chiều, là một ví dụ về một attribute directive. ngModel sửa đổi hành vi của một phần tử hiện có (thông thường là control <input>) bằng cách gán giá của thuộc tính vào control và cập nhật giá trị của control vào thuộc tính.

<input type="text" id="hero-name" [(ngModel)]="hero.name">

Angular có nhiều chỉ thị được định nghĩa trước hơn để thay đổi cấu trúc bố cục (ví dụ: ngSwitch) hoặc sửa đổi các khía cạnh của các phần tử và component DOM (ví dụ: ngStylengClass).

Tìm hiểu thêm trong hướng dẫn Attribute DirectiveStructural Directive.
AngularTypeScript
Bài Viết Liên Quan:
Trình khởi động bootstrap trong Angular
Trung Nguyen 26/07/2021
Trình khởi động bootstrap trong Angular

Trong hướng dẫn này, chúng ta sẽ tìm hiểu về trình khởi động bootstrap và cách Angular hoạt động bên trong và khởi động ứng dụng của chúng ta.

Cách tạo một dự án mới trong Angular
Trung Nguyen 25/07/2021
Cách tạo một dự án mới trong Angular

Trong hướng dẫn này, chúng tôi sẽ chỉ cho bạn cách sử dụng Angular CLI để tạo một dự án mới trong Angular.

Không gian làm việc và Cấu trúc file dự án
Trung Nguyen 22/07/2021
Không gian làm việc và Cấu trúc file dự án

Trong hướng dẫn này, bạn sẽ tìm hiểu về không dan làm việc và cấu trúc file dự án ứng dụng, dự án thư viện của Angular.

Service và Dependency Injection trong Angular
Trung Nguyen 21/07/2021
Service và Dependency Injection trong Angular

Trong bài viết này, bạn sẽ tìm hiểu vì sao Angular lại tách riêng component và service, cách sử dụng dependency injection để khởi tạo instance của service.