hocvietcode.com
  • Trang chủ
  • Học lập trình
    • Lập trình C/C++
    • Lập trình HTML
    • Lập trình Javascript
      • Javascript cơ bản
      • ReactJS framework
      • AngularJS framework
      • Typescript cơ bản
      • Angular
    • Lập trình Mobile
      • Lập Trình Dart Cơ Bản
        • Dart Flutter Framework
    • Cơ sở dữ liệu
      • MySQL – MariaDB
      • Micrsoft SQL Server
      • Extensible Markup Language (XML)
      • JSON
    • Lập trình PHP
      • Lập trình PHP cơ bản
      • Laravel Framework
    • Lập trình Java
      • Java Cơ bản
    • Cấu trúc dữ liệu và giải thuật
    • Lập Trình C# Cơ Bản
    • Machine Learning
  • WORDPRESS
    • WordPress cơ bản
    • WordPress nâng cao
    • Chia sẻ WordPress
  • Kiến thức hệ thống
    • Microsoft Azure
    • Docker
    • Linux
  • Chia sẻ IT
    • Tin học văn phòng
      • Microsoft Word
      • Microsoft Excel
    • Marketing
      • Google Adwords
      • Facebook Ads
      • Kiến thức khác
    • Chia sẻ phần mềm
    • Review công nghệ
    • Công cụ – tiện ích
      • Kiểm tra bàn phím online
      • Kiểm tra webcam online
Đăng nhập
  • Đăng nhập / Đăng ký

Please enter key search to display results.

Home
  • Angular
  • Học lập trình
  • Lập trình Javascript
ContentChild & ContentChildren trong Angular

ContentChild & ContentChildren trong Angular

  • 25-12-2023
  • Toanngo92
  • 0 Comments

Mục lục

  • Query single directive/component trong Angular
  • Query multiple content with ContentChildren
  • Listen to changes event trong Angular
  • Content và View trong Angular

Query single directive/component trong Angular

Chúng ta đã xem xét việc sử dụng Tab Component cùng với một component Counter để đếm số lượng component được khởi tạo. Bất ngờ thay, trong ví dụ dưới đây:

<app-bs-tab-group>
  <app-tab-panel title="Tab 1">
    content tab 1
    <app-counter></app-counter>
  </app-tab-panel>
  <app-tab-panel title="Tab 2">
    content tab 2
    <app-counter></app-counter>
  </app-tab-panel>
  <app-tab-panel title="Tab 3">
    content tab 3
    <app-counter></app-counter>
  </app-tab-panel>
</app-bs-tab-group>
<app-counter></app-counter>

Chúng ta hy vọng chỉ có một instance của counter, nhưng thực tế lại có đến 4 instances, chỉ có một instance được hiển thị. Khi có nhiều tab với các component phức tạp, và muốn chúng được khởi tạo chỉ khi cần thiết, chúng ta có cách nào không?

Có một giải pháp để TabPanelComponent nhận content và render nó khi cần. Chúng ta có thể sử dụng ContentChild để truy xuất một TemplateRef. Đầu tiên, chúng ta tạo một directive:

import { Directive } from "@angular/core";

@Directive({
  selector: "ng-template[tabPanelContent]",
})
export class TabPanelContentDirective {
  constructor() {}
}

Directive này sẽ thêm các tính năng lên một phần tử, trong trường hợp này là một thẻ ng-template có kèm theo attribute [tabPanelContent].

Tiếp theo, chúng ta sử dụng ContentChild để lấy directive đó:

export class TabPanelComponent implements OnInit, OnDestroy {
  @ContentChild(TabPanelContentDirective, { static: true, read: TemplateRef })
  explicitBody: TemplateRef<unknown>;
  constructor(private tabGroup: TabGroupComponent) {}
  ngOnInit() {
    this.tabGroup.addTabPanel(this);
  }
  ngOnDestroy() {
    this.tabGroup.removeTabPanel(this);
  }
}

Nhưng nếu chúng ta đặt debugger hoặc console.log, sẽ thấy nó trả về một instance của TabPanelContentDirective. Làm thế nào để chúng ta có thể lấy được TemplateRef instance?

Cách đơn giản là thay đổi cách đọc một element:

@ContentChild(TabPanelContentDirective, {static: true, read: TemplateRef}) explicitBody: TemplateRef<unknown>;

Bây giờ chúng ta chỉ cần thêm chút logic cho Tab component:

export class TabPanelComponent implements OnInit, OnDestroy {
  @ViewChild(TemplateRef, { static: true }) implicitBody: TemplateRef<unknown>;
  @ContentChild(TabPanelContentDirective, { static: true, read: TemplateRef })
  explicitBody: TemplateRef<unknown>;
  get panelBody(): TemplateRef<unknown> {
    return this.explicitBody || this.implicitBody;
  }
}

Với cách này, chúng ta chỉ có 2 instances được khởi tạo. Lưu ý rằng với các lazy initialize như vậy, mỗi khi active một tab, TemplateRef sẽ được tạo lại một lần.

Query multiple content with ContentChildren

ContentChildren là một cách để lấy các thành phần con (components, directives hoặc elements) mà chúng ta đã chèn vào trong một component cha thông qua cách sử dụng các thẻ template hoặc structural directives như ng-content.

Ví dụ, trong TabGroupComponent, nếu chúng ta có nhiều TabPanelComponent được chèn vào như sau:

<app-tab-group>
  <app-tab-panel></app-tab-panel>
  <app-tab-panel></app-tab-panel>
  <app-tab-panel></app-tab-panel>
</app-tab-group>

Chúng ta có thể sử dụng @ContentChildren để lấy danh sách các TabPanelComponent này trong TabGroupComponent:

import { Component, ContentChildren, QueryList, AfterContentInit } from '@angular/core';
import { TabPanelComponent } from 'đường dẫn tới TabPanelComponent';

@Component({
  selector: 'app-tab-group',
  template: `
    <ng-content></ng-content>
  `
})
export class TabGroupComponent implements AfterContentInit {
  @ContentChildren(TabPanelComponent) tabPanels: QueryList<TabPanelComponent>;

  ngAfterContentInit() {
    // Ở đây, tabPanels chứa danh sách các TabPanelComponent được chèn vào từ template của TabGroupComponent
    console.log(this.tabPanels);
  }
}

Với đoạn mã trên, khi TabGroupComponent được khởi tạo và các TabPanelComponent được chèn vào bên trong nó, biến tabPanels sẽ chứa danh sách các TabPanelComponent này. Điều này giúp chúng ta quản lý và tương tác với các thành phần con một cách thuận tiện hơn.

Listen to changes event trong Angular

ContentChildren là một cách để chúng ta lắng nghe và phản ứng khi có sự thay đổi về các thành phần con được chèn vào trong một component cha. Trong Angular, khi chúng ta sử dụng ContentChildren để lấy các thành phần con, chúng sẽ được khởi tạo trước khi ngAfterContentInit được gọi. Điều này tạo điều kiện tốt để chúng ta thực hiện các thao tác cần thiết khi các thành phần con thay đổi.

Ví dụ, trong TabGroupComponent, chúng ta muốn cập nhật tab được chọn khi có sự thay đổi về danh sách các tab:

import { Component, ContentChildren, QueryList, AfterContentInit, Output, EventEmitter } from '@angular/core';
import { TabPanelComponent } from 'đường dẫn tới TabPanelComponent';

@Component({
  selector: 'app-tab-group',
  template: `
    <ng-content></ng-content>
  `
})
export class TabGroupComponent implements AfterContentInit {
  @Input() tabActiveIndex = 0;
  @Output() tabActiveChange = new EventEmitter<number>();
  @ContentChildren(TabPanelComponent) tabPanelList: QueryList<TabPanelComponent>;

  ngAfterContentInit() {
    this.tabPanelList.changes.subscribe(() => {
      if (this.tabPanelList.length <= this.tabActiveIndex) {
        this.selectItem(0);
      }
    });
  }

  selectItem(idx: number) {
    this.tabActiveIndex = idx;
    this.tabActiveChange.emit(idx);
  }
}

Ở đoạn mã trên, khi danh sách các tabPanelList thay đổi (ví dụ: khi thêm hoặc xoá một TabPanelComponent), phương thức ngAfterContentInit sẽ lắng nghe sự kiện changes của tabPanelList và kiểm tra xem tabActiveIndex có hợp lệ không. Nếu không, nó sẽ chuyển đến tab đầu tiên. Điều này giúp chúng ta duy trì sự đồng bộ giữa các tabs và tab được chọn.

Content và View trong Angular

View và Content trong Angular có thể gây hiểu lầm về phần nào là phần hiển thị trực tiếp của component và phần nào là những gì được chèn vào từ bên ngoài. Để làm rõ điều này:

  • View: Đây là phần mẫu (template) mà component quản lý trực tiếp và hiển thị ra. Nó bao gồm tất cả những gì bạn định nghĩa cho component đó trong templateUrl hoặc template properties của @Component, trừ những phần được chèn vào thông qua ng-content. View có thể coi là “hộp đen” (black box) đối với các component khác và không thể trực tiếp truy cập vào nội dung bên trong.
  • Content: Là phần mẫu được chèn vào từ bên ngoài thông qua cặp thẻ mở và đóng của một component hoặc directive. Nó không được component quản lý trực tiếp. Nó thường được gọi là “light DOM”. Điều này đề cập đến nội dung được đưa vào component thông qua ng-content, là những phần tử hoặc dữ liệu được chèn vào component từ bên ngoài mà component không kiểm soát trực tiếp.

Bài viết liên quan:

Sắp xếp sủi bọt – Bubble Sort
TypeScript với Kiểu Dữ Liệu Cơ Bản – 3
TypeScript với Kiểu Dữ Liệu Cơ Bản – 2
TypeScript với Kiểu Dữ Liệu Cơ Bản – 1
Typescript cơ bản và cách cài đặt cho người mới
Thực Hành Micro Frontends
Dynamic Component trong Angular
Async Validator trong Angular Form
Reactive Forms Trong Angular (Phần 2)
Reactive Forms Trong Angular (Phần 1)
Template-driven Forms Trong Angular (Phần 2)
Template-driven Forms Trong Angular (Phần 1)

THÊM BÌNH LUẬN Cancel reply

Dịch vụ thiết kế Wesbite

NỘI DUNG MỚI CẬP NHẬT

2. PHÂN TÍCH VÀ ĐẶC TẢ HỆ THỐNG

1. TỔNG QUAN KIẾN THỨC THỰC HÀNH TRIỂN KHAI DỰ ÁN CÔNG NGHỆ THÔNG TIN

Hướng dẫn tự cài đặt n8n comunity trên CyberPanel, trỏ tên miền

Mẫu prompt tạo mô tả chi tiết bối cảnh

Một số cải tiến trong ASP.NET Core, Razor Page, Model Binding, Gabbage collection

Giới thiệu

hocvietcode.com là website chia sẻ và cập nhật tin tức công nghệ, chia sẻ kiến thức, kỹ năng. Chúng tôi rất cảm ơn và mong muốn nhận được nhiều phản hồi để có thể phục vụ quý bạn đọc tốt hơn !

Liên hệ quảng cáo: [email protected]

Kết nối với HỌC VIẾT CODE

© hocvietcode.com - Tech888 Co .Ltd since 2019

Đăng nhập

Trở thành một phần của cộng đồng của chúng tôi!
Registration complete. Please check your email.
Đăng nhập bằng google
Đăng kýBạn quên mật khẩu?

Create an account

Welcome! Register for an account
The user name or email address is not correct.
Registration confirmation will be emailed to you.
Log in Lost your password?

Reset password

Recover your password
Password reset email has been sent.
The email could not be sent. Possible reason: your host may have disabled the mail function.
A password will be e-mailed to you.
Log in Register
×