簡單地聊聊範本驅動表單(Template Driven Fomrs)後,應該會覺得範本變數(Template Variables)常常出現吧。範本變數讓我們很容易地在 HTML 上,透過宣告一個變數,來取得特定對象、使用特定對象的相關內容(屬性、方法...)。
今天,讓我們更深入地討論範本變數,並且搭配範本輸入變數(Template Input Variable)來玩玩:)
依據官方文件,範本變數可以參考的對象,幾乎可以說是 html 檔案中可以看到的的所有對象。但我們最常使用到的,應該是下列三種場景:
<app-stepper #tStepper></app-stepper>
<button type="button" (click)="tStepper.previous()">上一步</button>
<button type="button" (click)="tStepper.next()">下一步</button>
<Input>
的 value。<input #tPhone />
<button tpe="button" (click)="callPhone(tPhone.value)">撥打電話</button>
<ng-template></ng-template>
,搭配結構性指令 *ngIf
就像是在 html
檔案中使用預先準備好的模板一般,例如:<ng-container
*ngIf="heroList.length
then tHeroList"
else tNoData>
</ng-container>
<ng-template #tHeroList>
<app-hero-item
*ngFor="let hero of heroList"
[hero]="hero">
</app-hero-item>
</ng-template>
<ng-template #tNoData>
沒有英雄資料
</ng-template>
<Input>
上掛載 ngModel 指令時,就會產生一個 exportAs 的 ngModel 實例,此時,就可以將這個實例賦予給同標籤上的範本變數:<label for="email">Email</label>
<input
name="email"
id="email"
#tEmail="ngModel"
type="email"
ngModel
email
required/>
這樣就可以使用表單控制項(FormControl):
<!-- 當 tEmail 不合法的時候,就顯示這個 paragraph -->
<!-- 依據 errors 顯示驗證提示訊息 -->
<ol *ngIf="tName.invalid">
<li *ngIf="tName.errors?.required">此欄位必填</li>
<li *ngIf="tName.errors?.email">請輸入合法的 Email 格式</li>
</ol>
特別要提一下的是,在模組檔案中匯入 FormsModule 後。所有 <form>
標籤自動加上 ngForm 指令,這也是為什麼 <input>
需要先使用 ngModel 指令,才能將表單控制項的實例賦予給範本變數,而 <form>
就不必加上 ngForm 指令就可以將它的控制項賦予給範本變數:
<form #tForm="ngForm" (ngSubmit)="doSubmit(tForm.value)">
<input #tName="ngModel" ngModel/>
</form>
看了這項使用案例,大概就會有想像,可以組合這些東西完成好玩的事情吧!不僅如此,還有個東西叫做範本輸入變數(Template Input Variables),現在我們就在範本驅動表單上,使用範本變數加上範本輸入變數來玩玩檢核訊息吧!
在 HeroInformationForm 中,幾乎所有的欄位都是必填的。當使用者沒有填寫時,我們就要顯示「此欄位必填!」的訊息,同樣的錯誤訊息寫那麼多次實在有點煩躁...剛剛是不是說,有個東西可以像 html 檔案上可以呼叫的方法呢?讓我們這樣調整:
<!-- Template methods -->
<ng-template #tRequiredError>
<div>
This field is required!
</div>
</ng-template>
之後在每個需要顯示此資訊的地方,使用 *ngIf 來呼叫這個方法:
<ng-container
*ngIf="tName.invalid && tForm.submitted"
>
<ng-container
*ngIf="tName.errors?.required then tRequiredError">
</ng-container>
</ng-container>
如果 tName.errors.required
(檢核錯誤:必填)為真時,就會呼叫 tRequiredError 的 TemplateRef
,用它來替換 <ng-container>
容器。這樣,日後如果要填整檢核資訊,我們就只需要調整 #tRequiredError 所指的 <ng-template>
內容就可以了。
接下來,我們要搭配範本輸入變數,來進一步優惠這個必填檢核訊息:
<ng-template #tRequiredError let-fieldName="fieldName">
<div>
{{ fieldName }} is required!
</div>
</ng-template>
我們在這個 TemplateRef
上加上了輸入變數 fieldName
,並透過 let
的掛載,讓我們在使 <ng-template>
的範圍中,可以使用這個 fieldName
變數。
而使用方法是:
<div
*ngIf="tName.errors?.required"
class="error-message"
>
<ng-container
*ngTemplateOutlet="tRequiredError;
context: { fieldName: 'Name' }">
</ng-container>
</div>
只要使用 *ngTemplateOutlet 指令來放置 tReqiredError 此 TemplateRef
,就可以一併輸入 context 物件,在這個物件裡面將 fieldName 屬性賦予對應的欄位名稱,這樣會出現的檢核訊息就是:
很好玩吧哈哈!