Angular
cho phép chúng ta tạo ra giao diện của website dựa trên sự kết hợp giữa nhiều component khác nhau và để có thể giúp developer tạo ra các component có độ tái sử dụng(reusability) cao thì angular đã tạo ra một cơ chế giúp chúng ta nhúng template(html) bên ngoài vào các component, cơ chế này được gọi là content projection
.
ng-content
Cơ chế content projection
được thực hiện thông qua thẻ ng-content
do Angular cung cấp. Nếu chúng ta đặt thẻ <ng-content></ng-content>
vào file template(html
) của component A
thì ta có thể truyền bất cứ thẻ html nào hoặc bất cứ tập hợp của các thẻ html nào vào trong component A
thì các thẻ html đó sẽ được render ở vị trí mà <ng-content></ng-content>
được đặt trong template của component A
.
a.component.html
<div class="component-a">
<div class="component-a__header">
<h3>header của component a</h3>
</div>
<div class="component-a__body">
<ng-content></ng-content>
</div>
</div>
Trước khi mình nhúng template khác vào trong component A
.
<app-a></app-a>
Kết quả:
Khi mình nhúng các thẻ html vào component A
.
<app-a>
<div>
content bên ngoài component-a
</div>
<div>
content bên ngoài component-a
</div>
</app-a>
Kết quả:
Chúng ta cũng có thể nhúng một hoặc nhiều component khác vào component A
<app-a>
<app-b></app-b>
<app-c></app-c>
</app-a>
Kết quả:
Sử dụng nhiều thẻ ng-content cho cùng một component
Bạn cũng có thể đặt nhiều thẻ ng-content
trong cùng một template của một component, mỗi thẻ ng-content
ở một vị trí khác nhau, cho phép developer khác nhúng nhiều template vào các vị trí khác nhau trong component của bạn,
<div class="component-a">
<div class="component-a__header">
<h3>header của component a</h3>
</div>
<div class="component-a__body">
<h3>body</h3>
<ng-content></ng-content>
</div>
<div class="component-a__footer">
<h3>footer</h3>
<ng-content></ng-content>
</div>
</div>
Tuy nhiên, do Angular đang không thể phân biệt được phần template nào sẽ render tại vị trí của thẻ ng-content
nào nên nó sẽ render template bên ngoài ở vị trí của thẻ ng-content
nằm cuối cùng trong template của component A
.
<app-a>
<div class="body-content">
nội dung phân body
</div>
<div class="footer-content">
nội dung phần footer
</div>
</app-a>
Kết quả:
selector
Để phân biệt các thẻ ng-content
khác nhau, ta có thể truyền selector
(giống selector
khi bạn biết css cho các thẻ html) vào thuộc tính select
của các ng-content
khác nhau.
<div class="component-a">
<div class="component-a__header">
<h3>header của component a</h3>
</div>
<div class="component-a__body">
<h3>body</h3>
<!-- tìm thẻ html có class chứa body-content -->
<ng-content select=".body-content"></ng-content>
</div>
<div class="component-a__footer">
<h3>footer</h3>
<!-- tìm thẻ html có class chứa footer-content -->
<ng-content select=".footer-content"></ng-content>
</div>
</div>
Kết quả:
<div class="component-a">
<div class="component-a__header">
<h3>header của component a</h3>
</div>
<div class="component-a__body">
<h3>body</h3>
<!-- tìm thẻ html có tên là main -->
<ng-content select="main"></ng-content>
</div>
<div class="component-a__footer">
<h3>footer</h3>
<!-- tìm thẻ html có tên là footer -->
<ng-content select="footer"></ng-content>
</div>
</div>
Nhúng template vào component A
:
<app-a>
<main>
nội dung phân body
</main>
<footer>
nội dung phần footer
</footer>
</app-a>
Kết quả:
Có một số điều các bạn cần lưu ý đó là:
select
không phải là một Input củang-content
vì thế,<ng-content [select]="'main'"></ng-content>
sẽ tương tự với<ng-content></ng-content>
.select
không xử lý được dấu cách vì thế các bạn cũng không thể viết các selector phức tạp như khi các bạn query trong css được.
Lợi ích của việc áp dụng content injection
Việc tạo ra một component cho phép nhúng các template bên ngoài vào template của component đó sẽ giúp giúp chúng ta tái sử dụng tại một template trong nhiều layout khác nhau, đặc biết là những layout có chung một phần khung bao bên ngoài, nhưng nội dung thì lại có nhiều khác biệt.
Tuy ng-content
có rất nhiều tác dụng, nhưng nó vẫn có một điểm yếu, đó là chúng ta không thể truy cập vào các property hay các method của các component được truyền vào trong ng-content
.
Lời kết
Đôi khi thay vì việc sử dụng if else
để render layout cho từng trường hợp khác nhau thì việc sử dụng content inject
lại là một lựa chọn tốt hơn, nó sẽ giảm bớt gánh nặng về logic cho các component và tăng tính tái sử dụng cho chúng. Chúc các bạn một ngày làm việc vui vẻ và hiệu quả. Cheer !