angular--ng-template&ngTemplateOutlet的用法


 1.ng-template指令介紹--<ng-template></ng-template>

 ng-template表示一個模板,標簽內是模板的內容,模板的內容可以與其它模板一起組成組件模板。

在Angular中,我們用過的許多結構指令都使用了ng-template,如ngIf、ngFor和ngSwitch。

ngTemplate中的內容可以自定義,並且一開始不會被渲染,除非滿足一定的條件。我們必須使用結構指令去渲染它。

<ng-template>
    <button class="tab-button" (click)="login()">{{loginText}}</button>
    <button class="tab-button" (click)="signUp()">{{signUpText}}</button>
</ng-template>

上面代碼在頁面中並沒有被渲染。

2.ng-template使用

2.1ng-template與ngIf

我們見的最多的可能是與ngIf一塊使用,當if條件不成立時,將顯示else中的內容。下面代碼中else語句被指向了一個名為loading的模板,通過模板引用#loading的方式。

1 <div class="lessons-list" *ngIf="lessons else loading">
2   ... 
3 </div>
4 
5 <ng-template #loading>
6     <div>Loading...</div>
7 </ng-template>

其實,ngIf指令也是ng-template的包裝。

1 <ng-template [ngIf]="lessons" [ngIfElse]="loading">
2    <div class="lessons-list">
3      ... 
4    </div>
5 </ng-template>
6 
7 <ng-template #loading>
8     <div>Loading...</div>
9 </ng-template>

[ngIf]和[ngIfElse]為模板輸入變量。

2.2同一元素使用多個結構指令

1 <div class="lesson" *ngIf="lessons" 
2        *ngFor="let lesson of lessons">
3     <div class="lesson-detail">
4         {{lesson | json}}
5     </div>
6 </div>  

這樣會報錯:

Uncaught Error: Template parse errors:
Can't have multiple template bindings on one element. Use only one attribute 
named 'template' or prefixed with *

這意味着不能在同一個元素使用兩個或多個結構指令。

1 <div *ngIf="lessons">
2     <div class="lesson" *ngFor="let lesson of lessons">
3         <div class="lesson-detail">
4             {{lesson | json}}
5         </div>
6     </div>
7 </div>

可以在ngFor指令的外面包一層ngIf指令,這樣就解決了上面的問題;但這樣會額外創一個一個元素。因此,我們可以使用ng-container指令。

1 <ng-container *ngIf="lessons">
2     <div class="lesson" *ngFor="let lesson of lessons">
3         <div class="lesson-detail">
4             {{lesson | json}}
5         </div>
6     </div>
7 </ng-container>

ng-container的一種用途是,給我們提供一個附加指令的元素而不會創建一個額外的元素。另一種用途是,配合ngTemplateOutlet使用。

3.ngTemplateOutlet使用介紹

ngTemplateOutlet也是一個指令,它使用模板引用和上下文對象作為參數動態實例化模板。作為一個結構指令,我們可以使用它在DOM的各個部分插入模板(由ng-template創建)。

 1 <ng-container *ngTemplateOutlet="loading">This text is not displayed</ng-container> 

ngTemplateOutlet包含的任何內部內容都不會被渲染;我們可以根據需要向頁面添加任意數量的ngTemplateOutlet標簽,並實例化許多不同的模板。

 1 <div *ngTemplateOutlet="loading"></div>  

上面代碼中的div並不會被渲染,因為angular將上述內容替換成ng-template語法,

 1 <ng-template [ngTemplateOutlet]="template1"><div></div></ng-template> 

3.1傳遞數據給ngTemplateOutlet

我們可以通過ngTemplateOutletContext屬性傳遞數據

1 <ng-template let-value="value" #messageTemplate>  
2     <p>Value Received from the Parent is  {{value}}</p>
3 </ng-template>
1 <ng-container [ngTemplateOutlet]="messageTemplate" 
2        [ngTemplateOutletContext] ="{value:'1000'}">
3 </ng-container> 

當然,也可以使用簡寫屬性--context:

 1 <ng-container *ngTemplateOutlet="messageTemplate; context:{value:100}"></ng-container>  傳遞多個數據:

1 <ng-template let-name="nameVar" let-message="messageVar" #template>  
2   <p>Dear {{name}} , {{message}} </p>
3 </ng-template>
4  
5  
6 <ng-container [ngTemplateOutlet]="template" 
7           [ngTemplateOutletContext] ="{nameVar:'Guest',messageVar:'Welcome to our site'}">
8 </ng-container> 

傳遞對象:

1  
2 <ng-template let-person="person"  #template>  
3   <p>Dear {{person.name}} , {{person.message}} </p>
4 </ng-template>
5  
6  
7 <ng-container [ngTemplateOutlet]="template" 
8            [ngTemplateOutletContext] ="{ person:{name:'Guest',message:'Welcome to our site'} }">
9 </ng-container> 

使用$implicit:

可以在上下文對象中使用$implicit將其值設置為所有局部變量的默認值。

1 <ng-template let-name let-message="message" #template3>  
2   <p>Dear {{name}} , {{message}} </p>
3 </ng-template>
4  
5 <ng-container [ngTemplateOutlet]="templates" 
6               [ngTemplateOutletContext] ="{$implicit:'Guest',message:'Welcome to our site'}">
7 </ng-container> 

上面代碼中,我們沒有給 let-name 賦值,因此它從$implicit中獲取值。

3.2模板上下文

每個模板可以定義自己的輸入變量;實際上,每個模板都關聯了一個上下文對象,其中包含所有特定於模板的輸入變量。

 1 @Component({
 2   selector: 'app-root',
 3   template: `      
 4 <ng-template #estimateTemplate let-lessonsCounter="estimate">
 5     <div> Approximately {{lessonsCounter}} lessons ...</div>
 6 </ng-template>
 7 <ng-container 
 8    *ngTemplateOutlet="estimateTemplate;context:ctx">
 9 </ng-container>
10 `})
11 export class AppComponent {
12 
13     totalEstimate = 10;
14     ctx = {estimate: this.totalEstimate};
15   
16 }

說明:lessonsCounter為輸入變量,通過ng-template屬性使用前綴 let- 定義的

lessonsCounter對ng-template模板里面的內容是可見的,對模板外是不可見的。

lessonsCounter的值是由 estimate 決定的,故context 對象必須有一個estimate 的屬性。

3.3 模板引用

我們可以使用ViewChild裝飾器將模板直接注入到組件中:

 1 @Component({
 2   selector: 'app-root',
 3   template: `      
 4       <ng-template #defaultTabButtons>
 5           <button class="tab-button" (click)="login()">
 6             {{loginText}}
 7           </button>
 8           <button class="tab-button" (click)="signUp()">
 9             {{signUpText}}
10           </button>
11       </ng-template>
12 `})
13 export class AppComponent implements OnInit {
14 
15     @ViewChild('defaultTabButtons')
16     private defaultTabButtonsTpl: TemplateRef<any>;
17 
18     ngOnInit() {
19         console.log(this.defaultTabButtonsTpl); //undefined; ngAfterViewInit()才會打印
20     }
21 
22 }

模板可以被注入,就像DOM元素和組件一樣,通過將模板引用傳給ViewChild裝飾器。

我們還可以將模板作為一個輸入變量:

 1 @Component({
 2   selector: 'app-root',
 3   template: `      
 4 <ng-template #customTabButtons>
 5     <div class="custom-class">
 6         <button class="tab-button" (click)="login()">
 7           {{loginText}}
 8         </button>
 9         <button class="tab-button" (click)="signUp()">
10           {{signUpText}}
11         </button>
12     </div>
13 </ng-template>
14 <tab-container [headerTemplate]="customTabButtons"></tab-container>      
15 `})
16 export class AppComponent implements OnInit {
17 
18 }
 1 @Component({
 2     selector: 'tab-container',
 3     template: `
 4     
 5 <ng-template #defaultTabButtons>
 6     
 7     <div class="default-tab-buttons">
 8         ...
 9     </div>
10     
11 </ng-template>
12 <ng-container 
13   *ngTemplateOutlet="headerTemplate ? headerTemplate: defaultTabButtons">
14     
15 </ng-container>
16 ... rest of tab container component ...
17 `})
18 export class TabContainerComponent {
19     @Input()
20     headerTemplate: TemplateRef<any>;
21 }

當我們傳入自定義模板時(#customTabButtons),就顯示這個自定義模板;否則,顯示默認的模板。

3.4 ngTemplateOutlet、ng-template 與內容投影

父組件使用內容投影傳遞一個模板給子組件:

 1 import { Component, TemplateRef, Input, OnInit, ViewChild, AfterViewInit } from '@angular/core';
 2  
 3 @Component({
 4   selector: 'parent1',
 5   template: `
 6   
 7   <h1>Parent Component </h1>
 8  
 9   <child1> 
10     <p>This Template is Projected to the Child</p>
11   </child1>
12   `
13 })
14 export class Parent1Component {
15 }

子組件:

 1 import { Component, TemplateRef, Input, OnInit, ViewChild, AfterViewInit } from '@angular/core';
 2  
 3 @Component({
 4   selector: 'child1',
 5   template: `
 6  
 7   <h1>Child Component </h1>
 8  
 9   <ng-template #parentTemplate>
10     <ng-content></ng-content>
11   </ng-template>
12  
13   <ng-template [ngTemplateOutlet]="parentTemplate"></ng-template>
14  
15   `
16 })
17 export class Child1Component {
18 }
19  

4.總結

ng-template、ng-container和ngTemplateOutlet指令結合使用,可以創建高度動態和可定制的組件。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM