Angular 模板引用變量

2022-06-30 11:57 更新

模板變量

模板變量可以幫助你在模板的另一部分使用這個部分的數(shù)據(jù)。使用模板變量,你可以執(zhí)行某些任務,比如響應用戶輸入或微調應用的表單。

模板變量可以引用這些東西:

  • 模板中的 DOM 元素
  • 指令
  • 元素
  • TemplateRef
  • Web 組件

本章包含代碼片段的工作實例參閱現(xiàn)場演練 / 下載范例。

語法

在模板中,要使用井號 ?#? 來聲明一個模板變量。下列模板變量 ?#phone? 語法在 ?<input>? 元素上聲明了一個名為 ?phone ?的變量

<input #phone placeholder="phone number" />

可以在組件模板中的任何地方引用某個模板變量。這里的 ?<button>? 就引用了 ?phone ?變量。

<input #phone placeholder="phone number" />

<!-- lots of other elements -->

<!-- phone refers to the input element; pass its `value` to an event handler -->
<button (click)="callPhone(phone.value)">Call</button>

Angular 是如何為模板變量賦值的

Angular 根據(jù)你所聲明的變量的位置給模板變量賦值:

  • 如果在組件上聲明變量,該變量就會引用該組件實例。
  • 如果在標準的 HTML 標記上聲明變量,該變量就會引用該元素。
  • 如果你在 ?<ng-template>? 元素上聲明變量,該變量就會引用一個 ?TemplateRef ?實例來代表此模板。
  • 如果該變量在右側指定了一個名字,比如 ?#var="ngModel"? ,那么該變量就會引用所在元素上具有這個 ?exportAs ?名字的指令或組件。

將 NgForm 與模板變量一起使用

在大多數(shù)情況下,Angular 會把模板變量的值設置為它所在的元素。在前面的例子中, ?phone ?引用的是電話號碼 ?<input>? 。該按鈕的 click 處理程序會把這個 ?<input>? 的值傳給該組件的 ?callPhone()? 方法。

這里的 ?NgForm ?指令演示了如何通過引用指令的的 ?exportAs ?名字來引用不同的值。在下面的例子中,模板變量 ?itemForm ?在 HTML 中分別出現(xiàn)了三次。

<form #itemForm="ngForm" (ngSubmit)="onSubmit(itemForm)">
  <label for="name">Name</label>
  <input type="text" id="name" class="form-control" name="name" ngModel required />
  <button type="submit">Submit</button>
</form>

<div [hidden]="!itemForm.form.valid">
  <p>{{ submitMessage }}</p>
</div>

如果沒有 ?ngForm ?這個屬性值,?itemForm ?引用的值將是 HTMLFormElement 也就是 ?<form>? 元素。而 ?Component ?和 ?Directive ?之間的差異在于 Angular 在沒有指定屬性值的情況下,Angular 會引用 ?Component?,而 ?Directive ?不會改變這種隱式引用(即它的宿主元素)。

而使用了 ?NgForm ?之后,?itemForm ?就是對 ?NgForm ?指令的引用,可以用它來跟蹤表單中每一個控件的值和有效性。

與原生的 ?<form>? 元素不同, ?NgForm ?指令有一個 ?form ?屬性。如果 ?itemForm.form.valid? 無效,那么 ?NgForm ?的 ?form ?屬性就會讓你禁用提交按鈕。

模板變量的作用域

可以在包含此模板變量的模板中的任何地方引用它。而 結構型指令(如 ?*ngIf? 和 ?*ngFor? 或 ?<ng-template>? 同樣充當了模板的邊界。你不能在這些邊界之外訪問其中的模板變量。

同名變量在模板中只能定義一次,這樣運行時它的值就是可預測的。

在嵌套模板中訪問

內部模板可以訪問外模板定義的模板變量。

在下面的例子中,修改 ?<input>? 中的文本值也會改變 ?<span>? 中的值,因為 Angular 會立即通過模板變量 ?ref1 ?來更新這種變化。

<input #ref1 type="text" [(ngModel)]="firstExample" />
<span *ngIf="true">Value: {{ ref1.value }}</span>

在這種情況下,有一個包含這個 ?<span>? 的隱式 ?<ng-template>?,而該變量的定義在該隱式模板之外。訪問父模板中的模板變量是可行的,因為子模板會從父模板繼承上下文。

我們用更啰嗦的形式重寫上述的代碼,可以明確地顯示出 ?<ng-template>?。

<input #ref1 type="text" [(ngModel)]="firstExample" />

<!-- New template -->
<ng-template [ngIf]="true">
  <!-- Because the context is inherited, the value is available to the new template -->
  <span>Value: {{ ref1.value }}</span>
</ng-template>

但是,從外部的父模板訪問本模板中的變量是行不通的。

<input *ngIf="true" #ref2 type="text" [(ngModel)]="secondExample" />
<span>Value: {{ ref2?.value }}</span> <!-- doesn't work -->

這個更啰嗦的形式表明 ?ref2 ?位于外部的父模板中。

<ng-template [ngIf]="true">
  <!-- The reference is defined within a template -->
  <input #ref2 type="text" [(ngModel)]="secondExample" />
</ng-template>
<!-- ref2 accessed from outside that template doesn't work -->
<span>Value: {{ ref2?.value }}</span>

考慮下面這個帶 ?*ngFor? 的使用范例。

<ng-container *ngFor="let i of [1,2]">
  <input #ref type="text" [value]="i" />
</ng-container>
{{ ref.value }}

這里,?ref.value? 不起作用。結構型指令 ?*ngFor? 將模板實例化了兩次,因為 ?*ngFor? 在對數(shù)組中的兩個條目進行迭代。因此不可能定義出 ?ref.value? 指向的是誰。

對于結構型指令,比如 ?*ngFor? 或 ?*ngIf? ,Angular 也無法知道模板是否曾被實例化過。

結果,Angular 無法訪問該值并返回錯誤。

訪問 <ng-template> 的模板變量

在 ?<ng-template>? 上聲明變量時,該變量會引用一個 ?TemplateRef ?實例來表示該模板。

<ng-template #ref3></ng-template>
<button (click)="log(ref3)">Log type of #ref</button>

在這個例子中,單擊該按鈕會調用 ?log()? 函數(shù),它把 ?#ref3? 的值輸出到控制臺。因為 ?#ref ?變量在 ?<ng-template>? 上,所以它的值是一個 ?TemplateRef?。

下面是一個名為 ?TemplateRef ?的 ?TemplateRef()? 函數(shù)在瀏覽器控制臺中展開時的輸出。

▼ ? TemplateRef()
name: "TemplateRef"
__proto__: Function

模板輸入變量

模板輸入變量是可以在模板的單個實例中引用的變量。你可以用 ?let ?關鍵字聲明模板輸入變量,比如 ?let hero?。

在這個例子中,有幾個這樣的變量:?hero?、?i? 和 ?odd?。

<ng-template #hero let-hero let-i="index" let-odd="isOdd">
  <div [class]="{'odd-row': odd}">{{i}}:{{hero.name}}</div>
</ng-template>

此變量的范圍僅限于可復寫模板中的單個實例??梢栽谄渌Y構型指令的定義中再次使用相同的變量名。

相反,你可以通過在變量名稱前加上 ?#? 來聲明模板變量,如 ?#var?。模板變量引用其附加的元素、組件或指令。

模板輸入變量和模板變量名稱具有各自的名稱空間。?let hero? 中的模板輸入變量 ?hero ?和 ?#hero? 中的模板變量 ?hero ?是不同的。


以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號