Posted on Leave a comment

[功能介紹-9] Template-Driven Forms

使用Event由template表單傳送資料給Component

利用事件的$event去傳送相關資訊給component

<input (keyup)="onKey($event)">
  <p>{{values}}</p>

接收則可以透過event.target去存取該htmlInputElement的資料(詳細資料請見此
下面的範例能將value存至一個變數內且顯示在頁面上:

export class KeyUpComponent_v1 {
  values = '';

  onKey(event: any) { // without type info
    this.values += event.target.value + ' | ';
  }
}

模版驅動的表單

使用模版驅動的表單需要在app.module.ts裡面宣告我們要使用FormsModule這個library,宣告方式如下

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule }   from '@angular/forms';//使用模版表單驅動需要import這個模組

import { AppComponent }  from './app.component';
import { HeroFormComponent } from './hero-form/hero-form.component';

@NgModule({
  imports: [
    BrowserModule,
    FormsModule//在@ngModule裡去加上這個模組,這使應用程序可以訪問所有模板驅動的表單功能,包括。@NgModule、ngModel
  ],
  declarations: [
    AppComponent,
    HeroFormComponent
  ],
  providers: [],
  bootstrap: [ AppComponent ]
})
export class AppModule { }

使用ngModel對input的值與controller裡的變數做雙向繫結

下面這段code最主要要看的是[(ngModel)]="model.name",用這個標籤會自動將使用者輸入此input的值雙向綁定到model.name上面。

<input type="text" class="form-control" id="name"
       required
       &#91;(ngModel)&#93;="model.name" name="name">
你所輸入的資料是: {{model.name}}

然後在component也要有model這個屬性才能夠被綁定

export class HeroFormComponent {
  model ={};
}

成果如下:

ngModel會附加的class

狀態(State ) Class if true Class if false
被點擊接觸過 ng-touched ng-untouched
值被改變 ng-dirty ng-pristine
值不符合驗證 ng-valid ng-invalid

可以用下面的範例來觀察input元素class名稱的改變(#spy代表將這個input存到一個叫做spy的變數內)

<input type="text" class="form-control" id="name"
  required
  &#91;(ngModel)&#93;="model.name" name="name"
  #spy>
<br />TODO: remove this:  {{spy.className}}


下面是類別改變的狀態表

Show and hide validation error messages

在做表單驗證時,時常會有如下圖這樣的需求

若要使用表單驗證,需要在input宣告ngModel(不論有沒有做雙向綁定),或者宣告formControlName或formControl,不然無法驗證。
下面是一個最簡單的required驗證宣告:

<input name="fullName" ngModel required>

如果要用客製化的訊息去告訴使用者那邊輸入錯誤的話,則可以將ngModel的值輸出成一個模版變數#name

<label for="name">Name</label>
<input type="text" class="form-control" id="name"
       required
       &#91;(ngModel)&#93;="model.name" name="name"
       #name="ngModel">

在上面我們看到#name="ngModel",這是因為ngModel這個directive的exportAs的值剛好就是ngModel。
這代表將input的ngModel存進一個叫做name的變數裡,下面就可以使用這個ngModel的模型顯示相關的錯誤訊息。

<div &#91;hidden&#93;="name.valid || name.pristine"
     class="alert alert-danger">
  Name is required
</div>

pristine的意思是未被改變過的,而name.valid則是檢查所有我們所設定的驗證器,回傳是否合法或者不合法。
因此[hidden]="name.valid || name.pristine"的意思就是如果尚未填到該選項或者填入的值是合法的,則不顯示錯誤訊息。

現成的forms Validator

在上面的例子中,我們在input中下了required來做必填欄位的驗證。
required是一個directive,我們可以在這邊看到這個directive的詳細使用說明。
在說明網頁中,有幾個是需要去看的,首先就是selector,代表我們要如何去使用這個驗證器。
以required為例,有三種選擇required的方法如下圖:

這個圖代表了required不能用在checkbox,要使用這個directive要在input上加上required以及ngModel(或者formControl, formControlName)屬性。

其他Angular有提供的驗證器如下

客製化模板驅動表格驗證器

除了上述的內建驗證器之外,我們也可以自己製作自製的驗證器directive

@Directive({
  selector: '[forbiddenName]',
  providers: [{provide: NG_VALIDATORS, useExisting: ForbiddenValidatorDirective, multi: true}]
})
export class ForbiddenValidatorDirective implements Validator {
  @Input() forbiddenName: string;

  validate(control: AbstractControl): {[key: string]: any} {
    return this.forbiddenName ? forbiddenNameValidator(new RegExp(this.forbiddenName, 'i'))(control)
                              : null;
  }
}

在使用上的部份,就可以直接像下面這樣

<input id="name" name="name" class="form-control"
               required minlength="2" forbiddenName="bob"
               &#91;(ngModel)&#93;="hero.name" #name="ngModel" >
<div *ngIf="name.errors.forbiddenName">
            Name cannot be Bob.
          </div>

要注意的是,官網範例forbidden-name.directive.ts的selector名稱寫錯,不能使用appForbiddenName,要用forbiddenName,才能對的起來
這邊有ISSUE回報: Custom Validator example on angular.io directive selector issue.
詳情請見線上範例:live example

使用ngSubmit送出表單

在ngForm裡面,submit的button按下後並不會直接發生任何事,而是會觸發一個ngSubmit的事件,因此需要在form的地方去註冊ngSubmit事件

<form (ngSubmit)="onSubmit()" #heroForm="ngForm">

在上面的程式碼裡,我們將這個表單ngForm存至heroForm這個變數裡,因此在submit的按鈕可以存取ngForm裡的值來判段這個表單是否已通過驗證

<button type="submit" class="btn btn-success" &#91;disabled&#93;="!heroForm.form.valid">Submit</button>

參考資料

Leave a Reply