Sử dụng component trong angular

Sử dụng component trong angular là bài hướng dẫn cách tạo component, truyền tham số giữa các component, vòng đời component trong Angular

Giới thiệu về component trong Angular

Mỗi ứng dụng Angular là một tập hợp nhiều component, bởi vậy sử dụng component rất quan trọng. Khi tạo mới 1 project, Angular CLI  đã tạo sẵn cho bạn 1 component gốc có tên là AppComponent (đặt trong folder src/app), sau đó thì bạn có thể tạo các component con khác trong ứng dụng web của mình.

Một component trong Angular bao gồm 3 thứ:  template , class và metadata. Template còn gọi là view – là nơi bạn code html và hiển thị dữ liệu (trong class). Class là file .ts viết bằng ngôn ngữ typescript – nơi định nghĩa các hàm, khai báo và gán giá trị cho các biến, thực hiện xử lý, tính toán… Còn metadata là nơi khai báo các thông tin bổ sung, quản lý component của Angular.

AppComponent là component gốc, các component tạo ra sau là con của AppComponent này. Bạn có thể tạo nhiều component cho ứng dụng của mình như component Đăng nhập, Đăng ký, Sản phẩm bán chạy, Chi tiết sản phẩm, Bình luận, Liên Hệ, Giới thiệu…tùy nhu cầu. Trong mỗi component, file .ts là file coding chính.

Tạo component trong angular

Sử dụng component trong angular phải biết cách tạo nó. Để tạo component trong angular, dùng lệnh như sau: 

ng generate component [-t] [-s] TênComponent

Lệnh sẽ thực hiện các việc sau:

  1. Tạo một folder con trong app để chứa component
  2. Lệnh cũng tạo file <tên-component>.component.ts, đây là file class, nơi chứa code chính của component
  3. File có tên <tên-component>.component.html , đây là file template của component , còn gọi là view, nơi bạn sẽ code html và hiện dữ liệu.
  4. Tạo file <tên-component >.component.css, đây là file chứa các định dạng css cho các tag trong file view.
  5. File dùng cho mục đích test cũng được tạo, có tên file là <tên-component>.component.spec.ts
  6. Thêm 1 lệnh khai báo component trong file src/app/app.modules.ts

Các option của lệnh:

  • -t (–inline-template) : không tạo file html, dùng template ngay trong component
  • -s  (–inline-style) : không tạo file css, sử dụng css trực tiếp trong component

Ví dụ tạo component trong angular

Chạy lệnh  ng generate component SanPhamBanChay

– Các file , folder đươc tạo ra như sau:

– File san-pham-ban-chay.component.html mới chỉ có 1 dòng html. Bạn có thể xóa đi và code html tùy ý

– File san-pham-ban-chay.component.css có nội dung trống, bạn định dạng css tùy ý cho các tag trong file view của component.

– File có tên san-pham-ban-chay.component.ts có nội dung như bên dưới, đây là nơi bạn định nghĩa các biến, hàm… để dùng trong component

– Trong file app.modules.ts của Angulat được cập nhật để nhúng module mới tạo:

Ví dụ tạo component với cú pháp ngắn

Có thể tạo component với cú pháp ngắn hơn: ng g c sanPhamXemNhieu

Ví dụ: tạo component không cần có file template, css

Hiện component angular ra trang web

Để hiện nội dung component đã tạo, viết tag theo tên selector trong file .ts của component. Ví dụ:

Trong app.component.html (hoặc trong file view nào đó), code sau là để hiện thông tin trong component sản phẩm bán chạy đã tạo ở trên.

<app-san-pham-ban-chay></app-san-pham-ban-chay>

Xóa component angular

Để xóa compnonent đã tạo, bạn thực hiện thủ công bằng cách xóa folder component, sau đó mở file app.modules.ts rồi xóa lệnh import component + xóa tên component trong phần declaration.

Các chỉ thị thường dùng trong view Angular

Đây là một số chỉ thị thường dùng khi coding trong view của Angular, chúng giúp hiển thị dữ liệu trong view một cách uyển chuyển: *ngIf, *ngFor, *ngSwitch. Xem chi tiết ở đây nhé: Các chỉ thị thường dùng trong view Angular

Component lồng nhau

Trong mỗi ứng dụng angular, bạn sẽ phải tạo nhiều component để hiện thực các yêu cầu về nghiệp vụ. Như component sản phẩm bán chạy, sản phẩm hot, chi tiết sản phẩm, sản phẩm liên quan, bình luận, giỏ hàng, đăng ký…

Các component có thể lồng nhau, nghĩa là trong phần view của 1 component, bạn có thể nhúng view của 1 component khác (component con). Ví dụ:

– Tạo component dangnhap: ng g c dangnhap

– Thực hiện view con

<!-- dangnhap.component.html-->
<div class="formdangnhap text-white">
<p><label>Email</label><input type="email" class="form-control"> </p>
<p><label>Pass</label><input type="password" class="form-control"> </p>
<p><button class="bg-info p-2 border-0">Đăng nhập</button></p>
</div>

– Component con, chú ý giá trị selector, giá trị này sẽ dùng khi nhúng vào view cha.

//dangnhap.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'app-dangnhap',
  templateUrl: './dangnhap.component.html',
  styleUrls: ['./dangnhap.component.css']
})
export class DangnhapComponent implements OnInit {
  constructor() { }
  ngOnInit(): void { }
}

– Trong view cha, nhúng view con vào

<!-- app.component.html-->
<app-dangnhap></app-dangnhap>

Truyền dữ liệu giữa các component

Có 2 cách để truyền dữ liệu giữa các Component (cha -> con, con->cha) là @Input và @Output.

@Input: dùng để nhận giá trị từ ngoài truyền từ cha vào component.

@Output: Dùng để bắn giá trị từ con ra component cha mỗi khi có sự kiện gì đó (tùy bạn code) xảy ra trong view con. Trong @Output, bạn sử dụng đối tượng EventEmitter để thực hiện chuyển dữ liệu.

Ví dụ 1: sử dụng @Input trong component con để nhận dữ liệu từ cha

– Tạo component con

ng g c giohangTong

– Định nghĩa biến trong component cha

//app.component.html
tongSL:number= 12;
tongTienGH:number= 350000;

– Trong view của component cha, nhúng component con vào, truyền tham số tongSL tongTienGH

<!-- app.component.html-->
<app-giohang-tong [tongSL]="tongSL" [tongTienGH]="tongTienGH"></app-giohang-tong>

– Còn trong component con, dùng @Input để nhận 2 tham số truyền từ cha

//giohang-tong.component.ts
import { Input } from '@angular/core';
export class GiohangTongComponent implements OnInit {
  constructor() { }
  @Input() tongSL:number =0; 
  @Input() tongTienGH:number =0;
  ngOnInit(): void { }
}

– Trong view của component con, hiển thị các giá trị nhận được từ cha:

<!--giohang-tong.component.html-->
<div id="giohang_tong" class="giohang_tong">
    Bạn đã chọn <b>{{tongSL}}</b> sản phẩm. <br>
    Tổng tiền : <b>{{tongTienGH}}</b> VNĐ    
</div>

– Xem kết quả:

Ví dụ 2: sử dụng @Ourput để chuyển dữ liệu từ component con ra cha

– File view của component cha, nhúng component con vào, khi có sự kiện capnhatGH thì chạy hàm gan_TT_GH

<!-- app.component.html-->
<app-giohang (capnhatGH) ="ganSL_TT_GH($event)"></app-giohang>

– Còn trong file .ts của component cha, bạn định nghĩa hàm tiếp nhận dữ liệu từ con:

//app.component.ts
export class AppComponent {
  tongSL:number=0; 
  tongTienGH:number=0;
  ganSL_TT_GH(data=[0,0]) {//giả định component con bắn ra array data có 2 phần từ
    this.tongSL = data[0];
    this.tongTienGH= data[1];
  }
}

– Ở trong component con, dùng @Output định nghĩa sự kiện sẽ gọi cha và thực hiện gọi

//giohang.component.ts  (conponent con)
import { EventEmitter, Output } from '@angular/core';
export class GiohangComponent implements OnInit {
  @Output() capnhatGH = new EventEmitter();
  capnhat() {    
    let d = [ 10, 6000000]; 
    this.capnhatGH.emit(d);//thông qua EventEmitter bắn value ra cha, lúc này hàm gan_TT_GH trong cha sẽ chạy 
  }
}

– Trong view của componnent con, gọi hàm capnhat để bắn dữ liệu ra cha

<button (click)="capnhat()">Cập nhật</button>

Vòng đời của component trong Angular

Sử dụng component trong angular phải biết về vòng đời của nó. Vòng đời (lifecycle) của component tính từ lúc nó được tạo ra, rồi các sự kiện diễn ra trong nó, đến lúc cuối đời là component bị hủy. Angular có chức năng cho phép bạn thực thi các hàm của mình để có những can thiệp cần thiết trong vòng đời của từng component.

Sau đây là một số mốc (sự kiện) xảy ra trong vòng sống của component mà bạn cần biết: Changes, Init, DoCheck, AfterContentInitng, AfterContentChecked, AfterViewInit, AfterViewChecked, ngOnDestroy

Khi những sự kiện này của component xảy ra , bạn có thể làm gì đó tùy nhu cầu. Bằng cách nào? Bằng cách định nghĩa các hàm đặc biệt như liệt kê sau đây:

1. ngOnChanges

Trong component của bạn, nếu có định nghĩa hàm ngOnChanges thì hàm này sẽ chạy khi component dò thấy giá trị được binding vào component bằng phương pháp @Input có thay đổi.

Hàm ngOnChanges có 1 tham số kiểu SimpleChange, thông qua tham số này, bạn có thể truy xuất được giá trị mới, giá trị cũ trước và sau khi thay đổi. Ví dụ trong app.component.html có code nhúng component con giohang-tong

<!-- app.component.html -->
<app-giohang-tong [tongSL]="tongSL" [tongTienGH]="tongTienGH"></app-giohang-tong>

Vậy thì khi biến tongSL hoặc tongtienGH có thay đổi giá trị thì hàm ngOnChanges sẽ tự động chạy

//giohang-tong.component.ts
import { SimpleChanges } from '@angular/core';
export class GiohangTongComponent implements OnInit {
  constructor() { }
  @Input() tongSL:number =0; 
  @Input() tongTienGH:number =0;
  ngOnInit(): void { }
  ngOnChanges(changes: SimpleChanges) {
    if (changes['tongSL'].currentValue<=0) {
      changes['tongSL'].currentValue=0;
      changes['tongTienGH'].currentValue=0;
      this.tongSL=0;
      this.tongTienGH=0;
    }
    console.log(changes);  
  }
}

2. ngOnInit

Trong component, nếu bạn có định nghĩa hàm NgOnInit thì hàm này sẽ được gọi duy nhất 1 lần khi component được tạo, nó chạy sau khi hàm constructor và hàm ngOnchange (lần đầu). Trong hàm này bạn có thể thực hiện các công việc cần dùng khi conponent khởi tạo, như gán giá trị khởi đầu cho  các biến, gọi api, ghi log, khởi tạo form…

//giohang.component.ts
export class GiohangComponent implements OnInit {
  @Output() capnhatGH = new EventEmitter();
  tongSL:number = 0;
  tongTienGH:number=0;
  soluong1:number = 0;
  soluong2:number = 0;
  dongia1:number = 300;
  dongia2:number = 500;
  constructor() { }
  ngOnInit(): void { 
    this.soluong1=1;
    this.soluong2=1;
  }
}

3. ngDoCheck

Trong component, nếu bạn có định nghĩa hàm ngDoCheck thì hàm này sẽ chạy mỗi khi component phát hiện ra có sự thay đổi dữ liệu ở component. Hàm ngDoCheck() thực thi ngay sau hàm ngOnChanges() và ngOnInit() . Mời xem ví dụ:

export class GiohangComponent implements OnInit {
  tongSL:number = 0;   tongTienGH:number=0;
  soluong1:number = 0; soluong2:number = 0;
  dongia1:number = 300;dongia2:number = 500;
  constructor() { }
  ngOnInit(): void { this.soluong1=1; this.soluong2=1;}
  ngDoCheck(){
    console.log('Docheck');
    if (this.soluong1<0) { 
         alert("Số lượng phải >0"); 
         this.soluong1=1; 
    }
    if (this.soluong2<0) { 
        alert("Số lượng phải >0"); 
        this.soluong2=1; 
    }
  }
}

4. ngAfterContentInit

Nếu trong component bạn có định nghĩa hàm ngAfterContentInit thì nó sẽ chạy (1 lần) sau khi nội dung component đã được xây dựng thành công trong DOM , tức nội dung component đã được nạp vào trang web lần đầu thành công. Xem ví dụ cách viết code:

<!-- giohang.component.html-->
<br>Thời điểm hiện giỏ hàng: {{thoidiemHien|date:'dd/MM/Y H:m'}}
//giohang.component.ts
export class GiohangComponent implements OnInit {
  tongSL:number = 0;
  tongTienGH:number=0;
  soluong1:number = 0;
  soluong2:number = 0;
  dongia1:number = 300;
  dongia2:number = 500;
  thoidiemHien:number=0;
  constructor() { }
  ngOnInit(): void { 
      console.log('Hàm ngOnInit chạy');  
      this.soluong1=1; this.soluong2=1;
  }
  ngDoCheck(){ 
      console.log('Hàm ngDocheck chạy');
      if (this.soluong1<0){alert("Số lượng phải >0");this.soluong1=1;}
      if (this.soluong2<0){alert("Số lượng phải >0");this.soluong2=1;}
  }
  ngAfterContentInit(){ 
      console.log("Hàm ngAfterContentInit chạy"); 
      this.thoidiemHien=Date.now();
  }
}

5. ngAfterContentChecked

Trong component của bạn nếu có hàm ngAfterContentChecked thì nó sẽ chạy mỗi lần Angular dò thấy có sự thay đổi trong targets DOM content.

Hàm này chạy sau hàm ngAfterContentInit , nó có thể chạy nhiều lần tùy theo sự thay đổi dữ liệu trong DOM và có thể làm chậm hệ thống nếu bạn lạm dụng quá.

<!-- giohang.component.html-->
<h4>GIỎ HÀNG CỦA BẠN 
<span class="float-end mt-2 h6 text-danger"> 
  {{thoidiemHienHanh|date:'dd/MM/Y HH:mm:ss'}} 
</span>
</h4>
//giohang.component.ts
export class GiohangComponent implements OnInit {
  tongSL:number = 0;
  tongTienGH:number=0;
  soluong1:number = 0;
  soluong2:number = 0;
  dongia1:number = 300;
  dongia2:number = 500;
  thoidiemHien:number=0;
  thoidiemHienHanh:number=0;
  constructor() { }
  ngOnInit(): void { 
      console.log('Hàm ngOnInit chạy'); 
      this.soluong1=1; this.soluong2=1;
  }
  ngDoCheck(){
    console.log('Hàm ngDocheck chạy');
    if (this.soluong1<0){alert("Số lượng phải >0");this.soluong1=1;}
    if (this.soluong2<0){alert("Số lượng phải >0");this.soluong2=1;}
  }
  ngAfterContentInit(){
    console.log("Hàm ngAfterContentInit chạy"); 
    this.thoidiemHien= Date.now();
  }
  ngAfterContentChecked(){
    console.log("Hàm ngAfterContentChecked chạy");
    this.thoidiemHienHanh = Date.now();
  }
}

6. ngAfterViewInit

Hàm này tương tự như ngAfterContentInit nhưng nó chạy khi component và các component con của nó được khởi tạo thành công. Chỉ được gọi 1 lần sau khi ngAfterContentChecked.

//giohang.component.ts
ngAfterViewInit(){
    console.log("Hàm ngAfterViewInit chạy")
}

7. ngAfterViewChecked

Hàm ngAfterViewChecked được gọi chạy sau khi Angular dò thấy có sự thay đổi trong view của component cha và các view của component con

//giohang.component.ts
ngAfterViewChecked() {
    console.log("Hàm ngAfterViewChecked chạy")
}

8. ngOnDestroy

Trong component, nếu có hàm ngOnDestroy thì nó sẽ được gọi chạy 1 lần duy nhất trước khi component bị huỷ bởi Angular. Dùng hàm này nếu cần để hủy connection, unsubribe, xóa các biến trong stored…


Tóm tắt, việc sử dụng component trong angular là để kiến tạo nên các chức năng cần có trong ứng dụng web. Về mặt mô hình, có thể nói nôm na cho dễ hình dung : tổng các component tạo thành ứng dụng web. Tất nhiên bên cạnh component, bạn cần tạo thêm những thứ khác nữa như : service,directive, module… Từ từ tìm hiểu sau nhé.

Trong 1 ứng dụng angular , tạo nhiều component để hiện thực các chức năng muốn có
Trong 1 component, file .ts là code chính (typescript), file .html là các view của từng component. Các view này sẽ được nhúng vào view tổng (theo ngữ cảnh) để hiện thông tin cho user