第 12 天 范本变数加范本输入变数|template variables、template input variables

前情提要

简单地聊聊范本驱动表单(Template Driven Fomrs)後,应该会觉得范本变数(Template Variables)常常出现吧。范本变数让我们很容易地在 HTML 上,透过宣告一个变数,来取得特定对象、使用特定对象的相关内容(属性、方法...)。

今天,让我们更深入地讨论范本变数,并且搭配范本输入变数(Template Input Variable)来玩玩:)

范本变数的常用情景

依据官方文件,范本变数可以参考的对象,几乎可以说是 html 档案中可以看到的的所有对象。但我们最常使用到的,应该是下列三种场景:

  • 取得自订元件的 DOM:例如,取得自订的 Stepper 元件,这样就可以很容易地在 HTML 的按钮来使用 Stepper 元件的提供的上一步、下一步方法。
<app-stepper #tStepper></app-stepper>
<button type="button" (click)="tStepper.previous()">上一步</button>
<button type="button" (click)="tStepper.next()">下一步</button>
  • 取得 HTML 元素:例如,取得 <Input> 的 value。
<input #tPhone />
<button tpe="button" (click)="callPhone(tPhone.value)">拨打电话</button>
  • 取得 TemplateRef:取得 <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>
  • 搭配 FomsModule,取得 NgForm 或 NgModel 创建的表单控制项实例:这就是范本变数与范本驱动表单最常的搭配方式,当 <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 属性赋予对应的栏位名称,这样会出现的检核讯息就是:

https://ithelp.ithome.com.tw/upload/images/20210927/201283959jtfwYcNTI.png

很好玩吧哈哈!


<<:  如何衡量万事万物 (6) 衡量工具

>>:  【Day11】表单:非受控元件 Uncontrolled Component

[Day6] 注册API – model之AbstractUser

各位夥伴们大家好,今天是我们进入API阶段的第一天,在撰写API的逻辑之前,我们需要先到user\m...

【Day 24】半监督式学习(Semi-supervised Learning)(上)

我们知道监督式学习(Supervised Learning)就是有一堆Label好的训练资料,而半监...

Day 21 - SwiftUI开发学习5(文字填入)

今天我们来学习如何使用填入文字的物件 正文 文字填入 TextField 可以将文字填入进去。 如果...

视觉化的沟通框架 影响力地图impact mapping

今天要来分享的是产品经理在做需求管理、和对外沟通的时候,都很需要的一个思考框架 - 影响力地图 im...

第 28 天 - RxGesture

今天讲GitHub - RxSwiftCommunity/RxGesture,RxGesture是封...