Element
ng-content
https://ithelp.ithome.com.tw/articles/10187991
覺得有一點點像 vue 的
<component :is="component"></component>
ng-template
在說明 ng-template 之前,先從我們很常用到的 _ngIf 來說起,在 Angular 中 _ 星號代表 ng-template 的 sugar syntax,讓開發者簡化語法。所以下面的語法:
<div *ngIf="condition">Hello World!</div>
實際上就是下面語法的縮寫:
<ng-template [ngIf]= "condition" >
<div>Hello World!</div>
</ng-template>
那麼,<ng-template>到底是什麼東西呢?
The
<ng-template>is an Angular element for rendering HTML. It is never displayed directly. In fact, before rendering the view, Angular replaces the<ng-template>and its contents with a comment.
從官方文件中,我們可以知道,Angular Render 機制中並不會直接把這個 selector 和裡面所包含的內容顯示在最後 HTML 上。所以如果開發者沒有對 <ng-template> 進行額外處理,基本上就等於無用。
所以,該如何正確地使用 <ng-template> ?
首先,我們可以把 <ng-template> 想像成定義一個 template 的外框,你可以在裡面放入想要的 DOM。
<!--定義一個有你好文字和登出按鈕的 Template-->
<ng-template>
<h1>Hello Yu-Shuan!</h1>
<button>Logout</button>
</ng-template>
只有這樣寫是沒有任何作用的,所以我們可以透過 TemplateRef ,來決定 如何讓裡面的 DOM 顯示。根據官方文件說明:
You can access a TemplateRef via a directive placed on a element (or directive prefixed with *) and have the TemplateRef for this Embedded View injected into the constructor of the directive using the TemplateRef Token.
透過上述內容,我們可以知道,使用 <ng-template> 是獲得 TemplateRef 的方法之一 。在這邊的 TemplateRef 指的就是 <ng-template> 裡面的 DOM。當我們在 <ng-template> 放上 directive, 就能在 directive.ts 中 inject 這個 TemplateRef,並且控制 DOM 的顯示邏輯。
讓我們用最一開始的例子來解釋:
在 <ng-template> 內放入 ngIf, 而 ngIf 這個 directive 中會引用 TemplateRef ,以圖為例,TemplateRef 就是
<div>Hello World!</div>。
在引入 TemplateRef 之後, directive 內的邏輯會判斷 @input condition 是否為 true,是的話就在 viewContainerRef 中插入 templateRef,這樣呈現就會是我們想要的結果。
小結
- 只寫
<ng-template>而沒有寫上任何 directive 或是額外處理,其內容不會被顯示在最後 HTML 上。 - 我們在編寫 directive 時,可以透過
<ng-template>的幫助來取得TemplateRef(被 ng-template 所包住的 DOM)。
ng-container
說完 <ng-template>,再來談談 <ng-container>,其實 <ng-container> 比 <ng-template> 更單純,就是一個放置 DOM 的容器。 <ng-container> 這個 Tag 並不會顯示在 Html DOM 上,僅供 Angular 辨認使用。不過與 <ng-template> 不同的是,被 <ng-container> 所包住的 DOM 會顯示在畫面上,僅有 <ng-container> 這個 Tag 不顯示。
The
<ng-container>is a syntax element recognized by the Angular parser. It’s not a directive, component, class, or interface.
現在我們來改寫上面剛剛提到的 ngIf 例子:
<ng-template [ngIf]= "condition" >
<ng-container>
<div>Hello World!</div>
</ng-container>
</ng-template>
這樣的結果其實是一樣的,因為 <ng-container> 在最後 render 時並不會顯示,所以最後 render 出的 DOM 會和沒有寫 <ng-container> 的情況相同。
使用 ng-container 的時機
如果裡面內容會顯示,只有 <ng-container> 這個 Tag 不顯示,那為什麼要用 <ng-container>?當你發現沒有適合的 container 可以裝你想要的 DOM,就可以使用 ng-container。回到剛剛的例子,如果改用 <div *ngTemplateOutlet="greet"> 那 <div> 這個 Tag 就會顯示在最後的 HTML 上,假設你剛好有預設 <div> 的 CSS style,那有可能就會讓你裡面的 DOM 被影響到。
其他議題
等等!可是我看很多例子,都會看到 ng-container 和 NgTemplateOutlet 並用啊!為什麼沒有提到這個?
大家會在官方網站教學上,常常看到以下例子:
<!--這邊的 #greet 是指把這個 DOM 元素宣告成 variable,
然後就可以直接在下方引入此 variable(而此 variable 就是 templateRef)-->
<ng-container *ngTemplateOutlet="greet"></ng-container>
<ng-template #greet><span>Hello</span></ng-template>
現在來看看 ngTemplateOutlet 這個 Directive 的解釋:
Inserts an embedded view from a prepared TemplateRef.
讓我們把 <ng-container *ngTemplateOutlet="greet"></ng-container> 拆開來看:
1<ng-template [ngTemplateOutlet]="greet">
2 <ng-container></ng-container>
3</ng-template>
可以發現,以上面例子, <ng-container> 其實也可以用其他來取代,例如改用 div 寫成 <div *ngTemplateOutlet="greet"> 也沒啥不可以。
如果是用 ngIf 的情況,要用 ng-container 不然會顯示不出畫面
<ng-container *ngIf="open"> bla... </ng-container>