Angular:ng-template. ng-container的差異

做幾個簡單的範例來記錄ng-template. ng-container之間的差異

ng-template

單純只有<ng-template>不會顯示於畫面上。所以如果開發者沒有對 <ng-template> 進行額外處理(ex:[ngIf]. [ngFor]…),基本上就等於無用。

    <ng-template>
      <div>ng-template-1</div>
    </ng-template>

 

<ng-template>如果有加上[ngIf][ngFor]等額外處理的話的話,其內容才會出會於畫面。

    <ng-template [ngIf]="1==1">
      <div>ng-template-2</div>
    </ng-template>

 

上面的HTML,如果搭配建構型指令*ngIf的話,寫法如下。這種寫法等同於上面的寫法。<div *ngIf="condition"><ng-template [ngIf]="condition">的語法糖。普遍都是會用建構型指令這種寫法的。

並且會把div稱為是<ng-template>的宿主元素

    <div *ngIf="1==1">ng-template-3</div>
只要有使用到*ngIf語法糖的話,其元素稱為宿主元素。<ng-template>就像是個無形的容器,不會出現在DOM中。只要容器不符合出現的條件(ex:[ngIf]. [ngFor]…),那不管容器的宿主元素還是內容元素,都不會出現於DOM之中。反之,則只要容器有符合出現的條件(ex:[ngIf]. [ngFor]…),這樣容器的宿主元素跟內容元素就會顯示於Dom之中。
<div class="hello-world" *ngIf="1==1"> => 宿主元素
	Hello World~1
	<div class="qq">QQQ~</div> => 內容元素
</div>

<!--convert element-->
<ng-template [ngIf]="1==1">
	<div class="hello-world"> => 宿主元素
	Hello World~1
	<div class="qq">QQQ~</div> => 內容元素
	</div>
</ng-template>

 

另外我們接著來看看,把第二種寫法的<ng-template>替換成<div>的話,結果會是怎樣。可以看到跟第二種用法差異在,外層又多的一個<div>。如果只是單純的顯示結果可能這兩種用法沒有任何差異,但如果div有套用到css樣式的話,可能就會有影響了,為了避免這種問題,所以有了<ng-container>這個東西。

    <div *ngIf="1==1">
      <div *ngIf="1==1">ng-template-2_2</div>
    </div>

 

接下來看看如過ngIf的條件不成立的話,會發生什麼事。結果也是什麼都沒有

    <div *ngIf="1!=1">
      <div *ngIf="1==1">ng-template-4</div>
    </div>   

 

測試結果:

前端畫面顯示結果

 

那這樣<ng-template>有什麼用途呢?如果我們在畫面上有一個區塊是網頁載入時先不顯示的,等到特定條件被觸發後再顯示出來,這時後就可以用到<ng-template>了,範例如下:

<div *ngIf="show; else notshow">
   當 show = true 時,顯示這些內容
</div>
<ng-template #notshow>
   當 show = false 時,顯示這些內容
</ng-template>

 

總結:
1.比較會出現寫結構性變化時,會使用到 <ng-template>
2.<ng-template>裡面的元素可以透過TemplateRef取得


ng-container

跟<ng-template>不一樣。<ng-container>不用加上[ngIf][ngFor]等額外處理的話,其宿主元素內容直接顯示於畫面。

    <ng-container>
      <div>ng-container-1</div>
    </ng-container>

 

搭配建構型指令*ngIf也是可以的喔。

    <ng-container *ngIf="1==1">
      <div>ng-container-2</div>
    </ng-container>

 

接下來看看如過ngIf的條件不成立的話,會發生什麼事。結果也是什麼都沒有

    <ng-container *ngIf="1!=1">
      <div>ng-container-2</div>
    </ng-container>

 

<ng-template> & <ng-container>差異比較:

看到這邊可以發現,<ng-template><ng-container>用法其實是沒差太多的。既然沒有差太多,就表示還是有差異之處,讓我們來看看差在哪裡。我們先用三種寫法來呈現ngFor效果。

    <!-- 使用ng-template + ngFor -->
    <ng-template ngFor let-data [ngForOf]="datas">
      <div>hello angular - ng-template for {{data}}</div>
    </ng-template>

    <!-- 使用ng-container + ngFor -->    
    <ng-container *ngFor="let data of datas">
      <div>hello angular - ng-container for {{data}}</div>
    </ng-container>
    
    <!-- 使用div + ngFor -->    
    <div *ngFor="let data of datas">
      <div>hello angular - div for {{data}}</div>
    </div>


ng-template ngForng-container *ngFor所呈現出來的HTML是一樣的,但因為ng-template不能使用建構型指令(*ngFor),寫法比較繁瑣,所以比較常使用的是ng-container *ngFor

ng-container *ngFordiv *ngFor的差別在於HTML的呈現,ng-container + ngFor不會顯示出HTML Tag,但是div+ ngFor則會顯示出實體div Tag,如果沒有div沒有套用css樣式的話,是沒有什麼影響。但是div如果有套用css樣式的話,多了一層div,前端畫面可能就會受到影響了。透過上面的測試應該有比較了解ng-container的用法了。

至於div *ngFor則會顯示出實體div Tag的原因是,div *ngFor其實是Angular的語法糖,實際上是用ng-template ngFor去包裝的,前面介紹<ng-template>時有提到,只要<ng-template>有符合出現的條件(ex:[ngIf]. [ngFor]…),宿主元素就會顯示於Dom之中,所以顯示出的第一個div為宿主元素,接在在顯示第二個div(內容元素),所以會有兩個div,如前面所說,如果我們對div有套用css樣式的話,多了一層div,前端畫面可能就會受到影響了。

如果使用ng-container *ngFor,就沒有宿主元素的問題,就不會多顯示出一個沒有用途的宿主元素div了。

 

總結:
1.常見的使用情境是不想要多寫不必要的 html ,例如 div、span 等,但又想要將一個區塊的 html 包起來處理,就會使用到 <ng-container>


ng-content & ngTemplateOutlet


 
 
Ref:
1.一文了解 ng-template, ng-content, ng-container, 和 *ngTemplateOutlet的区别
2.Angular - ng-template & ng-container
3.ngTemplate VS ngContainer