ngTemplateOutlet trong Angular
- 22-12-2023
- Toanngo92
- 0 Comments
Mục lục
ng-template trong Angular
ng-template
trong Angular là một công cụ mạnh mẽ cho phép chúng ta xác định mẫu hoặc dạng của một đoạn mã HTML mà không render ngay lập tức trên giao diện người dùng.
Khi bạn bao bọc đoạn mã HTML bằng ng-template
, nó không được hiển thị ngay lập tức khi trình duyệt tải trang. Thay vào đó, nó chỉ xuất hiện trong một số trường hợp cụ thể, như khi sử dụng *ngIf
với điều kiện else hoặc thông qua ngTemplateOutlet
(một chức năng khác sẽ được đề cập sau).
Tên “ng-template
” cũng gợi lên ý nghĩa của nó. Template có thể hiểu đơn giản như một mẫu, một dạng. Dù việc dịch sang tiếng Việt có thể không trực tiếp, nhưng khi kết hợp nhiều template với nhau, chúng ta có thể tạo ra một giao diện người dùng hoàn chỉnh, đầy đủ chức năng.
Từ những điểm này, ta có thể hiểu ng-template
là một phần của Angular dùng để định nghĩa và render mã HTML một cách linh hoạt. Những phần mã HTML nằm trong ng-template
sẽ không được hiển thị trực tiếp trên trang web mà chỉ xuất hiện khi được kích hoạt thông qua các điều kiện hoặc kỹ thuật Angular khác.
Khi nào thì nên dùng ng-template
Ng-template trong Angular thường được sử dụng trong những trường hợp cụ thể, và từ kinh nghiệm của mình, đây là một số tình huống thường gặp khi bạn nên áp dụng ng-template:
- Kết hợp với các Structure Directive: Ví dụ như sử dụng
*ngIf
để quyết định việc hiển thị một phần tử dựa trên điều kiện. Ng-template có thể giúp xác định cách hiển thị nội dung dựa trên các điều kiện này. - Khi có phần UI lặp lại trong cùng một component: Đôi khi, có một số phần của giao diện người dùng trong một component được lặp lại nhiều lần, nhưng lại quá nhỏ để tách riêng thành một component mới.
Ví dụ, giả sử bạn có một component chứa biến counter và phần UI của counter này được lặp lại trong component của bạn vài lần, nhưng UI vẫn giống nhau.
Thay vì sao chép và dán mã code nhiều lần, bạn có thể sử dụng ng-template
và ngTemplateOutlet
như sau:
<div class="card">
<div class="card-header">
You have selected
<ng-container [ngTemplateOutlet]="counterTmpl"></ng-container>.
</div>
<div class="card-body">
There are <ng-container [ngTemplateOutlet]="counterTmpl"></ng-container> was
selected.
</div>
<div class="card-footer">
You have selected
<ng-container [ngTemplateOutlet]="counterTmpl"></ng-container>. ::
<ng-template #counterTmpl>
<span class="badge badge-primary">{{ counter }}</span> items
</ng-template>
</div>
</div>
Ưu điểm rõ rệt khi sử dụng ng-template
là khi cần điều chỉnh UI cho counter. Thay vì phải chỉnh sửa ở nhiều vị trí, bạn chỉ cần sửa template của counter. Điều này giúp tránh những lỗi như việc nhập sai hoặc quên sửa các vị trí tương ứng.
Với việc gói gọn mã code trong một template, việc sử dụng ng-template
còn thuận tiện hơn việc tách phần counter ra thành một component mới.
Dùng ng-template để pass vào component khác. Hỗ trợ override template có sẵn trong component.
Sử dụng ng-template
để chuyển template vào một component khác là một cách mạnh mẽ để điều chỉnh giao diện theo ý muốn. Ví dụ, nếu bạn có một component tab-container
mà mặc định hiển thị các tab với một template gọi là defaultTabButtonsTmpl
:
@Component({
selector: "tab-container",
template: `
<ng-template #defaultTabButtonsTmpl>
<div class="default-tab-buttons">...</div>
</ng-template>
<ng-container *ngTemplateOutlet="headerTemplate || defaultTabButtonsTmpl"></ng-container>
... phần còn lại của component tab container ...
`,
})
export class TabContainerComponent {
@Input() headerTemplate: TemplateRef<any>; // Template tùy chỉnh được cung cấp từ component cha
}
Tuy nhiên, khi bạn sử dụng tab-container
, bạn hoàn toàn có thể truyền vào một template mới để ghi đè lên giao diện mặc định từ component cha:
@Component({
selector: 'app-root',
template: `
<ng-template #customTabButtons>
<div class="custom-class">
<button class="tab-button" (click)="login()">
{{loginText}}
</button>
<button class="tab-button" (click)="signUp()">
{{signUpText}}
</button>
</div>
</ng-template>
<tab-container [headerTemplate]="customTabButtons"></tab-container>
`
})
Ở đây, #customTabButtons là một template mới, chứa các button tab với nội dung bạn muốn. Khi bạn truyền template này vào tab-container
thông qua [headerTemplate], nó sẽ ghi đè lên template mặc định và hiển thị giao diện mới mà bạn đã tạo ra. Điều này giúp bạn linh hoạt điều chỉnh giao diện một cách dễ dàng hơn từ component cha mà không cần phải sửa đổi trực tiếp trong component con.
ngTemplateOutlet trong Angular
NgTemplateOutlet
trong Angular giúp render một template được tạo bởi ng-template
lên giao diện người dùng. Cú pháp sử dụng có thể là ngTemplateOutlet="templateRef"
hoặc [ngTemplateOutlet]="templateRef"
. Cần lưu ý rằng dấu sao (*) là quan trọng và nếu thiếu sẽ không hoạt động.
Tương tự như việc component sử dụng @Input() để nhận dữ liệu từ bên ngoài, ng-template
cũng có cú pháp tương tự để truyền dữ liệu thông qua ngTemplateOutletContext
.
Ví dụ, bạn muốn tái sử dụng một button với nhiều tùy chọn khác nhau như: một button chỉ có chữ, một button có chữ và icon, hoặc một button không có icon.
Để làm điều này, bạn có thể sử dụng kết hợp giữa ng-template
, ngTemplateOutlet
và ngTemplateOutletContext
:
<ng-template
#buttonTmpl
let-label="label"
let-className="className"
let-icon="icon"
>
<button [ngClass]="['btn', className ? className : '']">
<i *ngIf="icon" class="fa {{icon}}"></i>
{{ label }}
</button>
</ng-template>
<ng-container
[ngTemplateOutlet]="buttonTmpl"
[ngTemplateOutletContext]="{ label: 'Click here', className: 'btn-primary', icon: null }"
>
</ng-container>
<ng-container
[ngTemplateOutlet]="buttonTmpl"
[ngTemplateOutletContext]="{ label: 'Remove', className: 'btn-danger', icon: 'fa-remove' }"
>
</ng-container>
Mặc dù có nhiều code hơn, nhưng giờ đây bạn có thể tái sử dụng button này trong cùng một component hoặc truyền template này vào các component khác mà không gặp vấn đề gì.
Một số điểm cần lưu ý:
- Khi định nghĩa
ng-template
, bạn có thể cấu hình cho template nhận giá trị thông qua cú pháplet-name="name".
Tên bên trái dấu bằng là biến bạn có thể truy cập trongng-template
, còn tên bên phải dấu bằng là tên của thuộc tính của đối tượng khi truyền quangTemplateOutletContext
. Hai tên này hoàn toàn có thể khác nhau, không gây vấn đề gì. - Nếu không đặt tên cho biến bên phải của dấu bằng, chỉ viết
let-name
, khi truyền dữ liệu qua context, thuộc tính của đối tượng truyền vào sẽ được gán là$implicit
. - Khi sử dụng biến trong
ng-template
, bạn có thể mất đi sự an toàn kiểu dữ liệu. Ví dụ, nếu bạn truyền một đối tượnguser
vớifirstName
,lastName
vàage
qua cú pháplet-user="user"
, và bạn cố gắng truy cậpuser.fullName
trongng-template
, Angular không thể phát hiện và báo lỗi cho bạn trước cả khi biên dịch.
ng-container trong Angular
ng-container
trong Angular là một thành phần giúp render nội dung mà không tạo ra thẻ HTML mới trong DOM, giúp tránh ảnh hưởng đến việc viết style.
Ví dụ, nếu bạn sử dụng [ngTemplateOutlet
] và [ngTemplateOutletContext]
trong một thẻ div:
<div
[ngTemplateOutlet]="buttonTmpl"
[ngTemplateOutletContext]="{ label: 'Click here', class: 'btn-primary', icon: null }"
></div>
Khi render ra UI, mặc dù bạn chỉ sử dụng một div, nhưng nó vẫn tạo ra một thẻ div bao ngoài nội dung bạn render:
<div>
<button class="btn btn-primary">Click here</button>
</div>
Nếu bạn sử dụng kiểu CSS chặt chẽ theo cấu trúc parent > child
, thêm một thẻ div thừa có thể ảnh hưởng đến giao diện của bạn vì style của div này có thể không phù hợp với cấu trúc CSS của bạn.
Vì vậy, sử dụng ng-container
giúp tránh tạo ra các thẻ HTML thừa, giữ cho cấu trúc của DOM gọn gàng hơn, đồng thời không làm ảnh hưởng đến việc viết style dựa trên cấu trúc parent > child
.