Template variable 可以让你在 template 的任意一处使用被标记过的 HTML 元件的数据,例如响应使用者的输入或微调应用程序的表单,简单来说当你在画面中有一个 <input>
,除了透过 Form 获得使用者在这个 <input>
所以输入的数据之外,也可以透过将这个 <input>
设定为 template variable,这样就可以让在别的地方的 <button>
中的 event binding 获得这个 <input>
的数据,详细的内容让我们继续看下去吧。
要将 template 中的元件声明为 template variable,需要在这个元件上加上哈希符号 #
,举个例子
<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>
虽然在 template 中 <button>
离 <input>
很远,但因为<input>
透过 # 被标记为 template variable,所以远处的 <button>
可以透过呼叫 phone.value 获取这个 <input>
的值。
了解了 template variable 後,接着要来介绍 Angular 是如何根据你声明变量的位置为 template variable 分配一个值:
<ng-template>
上声明变量,则该变量引用一个 TemplateRef
的 instance,它代表着这个 template,这个之後会详细介绍在大多数情况下,Angular 将 template varibale 的值设置为他出现的元素,比如上面的例子,phone 是指 <input>
,而点击了按钮则会将 <input>
的内容传递给 component 中的 callPhone() method。
不过也可以透过在变量右边指定一个名称达到其他的效果,比如说可以使用 NgForm directive 来达到 Form 的效果,他通过引用 directive 的 exportAs name 来获取对不同值得引用,来举个例子吧
在 app.component.ts 中加入 property 与 method
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
submitMessage: string = ''; // (1)
onSubmit($event: any) { // (2)
this.submitMessage = $event.form.value.name;
}
}
<input>
的值在 app.component.html 中添加 <form>
<!-- app.component.html -->
<form #itemForm="ngForm" (ngSubmit)="onSubmit(itemForm)">
<label for="name"
>Name <input class="form-control" name="name" ngModel required />
</label>
<button type="submit">Submit</button>
</form>
<div [hidden]="!itemForm.form.valid">
<p>{{ submitMessage }}</p>
</div>
如果没有在 #itemForm 右边使用 ngForm
则 #itemForm 的引用值将是 HTMLFormElement
的 <form>
元件,但这边是使用了 ngForm
所以 #itemForm 是对 NgForm directive 的引用,他可以跟踪表单中的每一个可控制元件的值和有效性,这与原生的 <form>
元素不同,NgForm directive 中有一个 property,他用於检测整个表单的有效性,所以当 itemForm.form.valid 无效时,则整个 NgForm 会将 submit 按钮 disable。
既然提到 variable 就不免俗的要提到 scope,至於什麽是 scope?简单来说 scope 就是一个变数的生存范围,一但超出了这个范围就无法存取到这个变数
至於详细的内容可以看我这一篇 [JS] You Don't Know JavaScript [Scope & Closures] - What is Scope? 文章中有详细的介绍什麽是 scope。
而 template variable 则可以在 template 中的任何一个位置中调用到,但是 Structural directive
(*ngIf, *ngFor, <ng-template>
...) 他会充当 template 的边界,所以你会无法访问到 Structural directive 内部的 template variable。
就如同 Javascript 的 scope 一样,template 中内部的 template 可以访问外部 template 的变量,但相反的话不行,举个在同层级的例子
<input #ref1 type="text" [(ngModel)]="firstExample" />
<span *ngIf="true">Value: {{ ref1.value }}</span>
当更改了 <input>
的内容时会立即更改 <span>
中的内容,因为 Angular 会立即通过 template variable ref1 来更新内容,接着再举一个由内部访问到外部变量的例子
<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>
像上面提到的,<ng-template>
会创造一个新的 template 范围,但是因为在这个新的 template 范围中的 <span>
是从内部访问外部的变量 ref1,所以是可以正常访问到的,就跟 Javascript 一样
const ref1 = 'input value';
function spanValue() {
console.log(ref1); // input value
}
虽然 ref1 与 function spanValue 是不同的 scope,但因为内部可以访问外部变量,所以可以将 ref1 给 console 出来,接着来看父层如果访问子层变量会发生什麽事
<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>
如果是上面例子的情况,<span>
会无法获得 ref2 的内容,因为对於 ref2 来说他是存在於子层的变量,所以无法透过父层呼叫到,就跟 Javascript 一样
function inputScope() {
let ref2 = 'in child scope';
}
console.log(ref2); // Uncaught ReferenceError: ref2 is not defined
外部无法呼叫到内部 scope 的变量,所以在使用 template variable 时要记得存取变量的规则, 外部 scope 无法存取到内部 scope 的变量
。
本章中介绍了什麽是 template variable 与他的使用方法,简单来说就是可以利用他获得其他 element 的内容,不过因为他也是属於变量所以也会有 scope 的问题,要记住外部 scope 是无法访问到内部 scope 的变量的,而使用了 Structural directive
则会创造一个独立的 template 让整个 template 出现父子层的现象,就跟在 javescript 中使用 function 建立 function scope 一样,所以要特别注意。
而本篇也是讲解 template 的最後一篇,明天开始将会进入到 directive,这个观念在前面多多少少都有提到一点,但没关系之後会详细地对他进行讲解,那我们就明天见吧。
<<: D12 - 如何用 Apps Script 寄出客制化的表单并搜集分散在 Google Sheet 中的回应?(二)大幅度客制你的 Google Form
Q1. 什麽是 php 反序列化? 为了让程序中的物件可以在保存到 persistent datab...
graceful shutdown 在关闭服务前,在服务内部以做完该做的事情,使得服务得以善终。 在...
30天的挑战就这样结束了,现在的心情怎麽有些空虚呢?? 哈哈哈,为什麽会这样呢??我想跟题目有关吧,...
写在前面 基本上分享会很随意, 主要就是纪录一些我觉得有趣或是 Kaggle 这系列想传达一些 py...
JavsScripe是一套非同步的、单执行绪(single-threaded)语言,任务与任务之间必...