ng-conf-2017 - Angular Form Validation

目錄

  • 第一節(jié) - 驗(yàn)證概述
  • 第二節(jié) - 設(shè)置基本的驗(yàn)證
  • 第三節(jié) - 即將到來(lái)的驗(yàn)證功能

第一節(jié) - 驗(yàn)證概述

overview-form-control

同步驗(yàn)證器

validator-fn

同步驗(yàn)證器函數(shù)

tambourineValidator(ctrl: AbstractControl): ValidationErrors | null {
  return ctrl.value === 'tambourine' ? null :
    {tambo: {expected: 'tambourine', actual: ctrl.value }};
}

異步驗(yàn)證器

async-validator-fn

異步驗(yàn)證器函數(shù)

myAsyncValidator(ctrl: AbstractControl): Observable<ValidationErrors|null> {
  return this._http.get(`my/endpoint?username=${ctrl.value}`)
    .map(resp => resp.json().exists ? {exists: true} : null);
}

第二節(jié) - 設(shè)置基本的驗(yàn)證

json-server 簡(jiǎn)介

json-server 用于基于 JSON 數(shù)據(jù)快速地創(chuàng)建本地模擬的 REST API。

json-server 的安裝

$ npm install -g json-server

json-server 的使用

$ json-server --watch bids.json

Angular CLI 代理配置

創(chuàng)建 proxy.conf.json 文件

{
  "/bids": {
    "target": "http://localhost:3000",
    "secure": false
  }
}

更新 package.json 文件

{
  "scripts": {
    "start": "ng serve --proxy-config proxy.conf.json",
  }
}

創(chuàng)建 bids.json 文件

{
  "bids": [
    {
      "id": 1,
      "name": "Semlinker",
      "bid": "10"
    }
  ]
}

同步驗(yàn)證與異步驗(yàn)證示例

AppModule

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import {ReactiveFormsModule} from "@angular/forms";
import {HttpModule} from "@angular/http";

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpModule,
    ReactiveFormsModule
  ],
  providers: [
    {provide: 'config', useValue: {databaseURL: 'http://localhost:3000'}}
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

AppComponent

import {Component, OnInit, Inject} from '@angular/core';
import {FormGroup, FormControl, Validators, 
  AbstractControl, ValidationErrors} from "@angular/forms";
import {Http} from "@angular/http";

import {Observable} from "rxjs/Observable";
import 'rxjs/add/operator/map';

interface Bid {
  id: number;
  name: string;
  bid: number
}

@Component({
  selector: 'app-root',
  template: `
    <ul *ngIf="bids">
      <li *ngFor="let bid of bids">
        {{bid.name}}: {{bid.bid}}
      </li>
    </ul>
    <div>
       <p>New Bid</p>
       <form [formGroup]="form">
          <input type="text" placeholder="Name" 
            formControlName="name">
          <div class="errors" *ngIf="name.invalid && name.touched">
            Name is required.
          </div>
          <input type="number" placeholder="Bid" 
            formControlName="bid">
          <div class="errors" *ngIf="bid.invalid && bid.touched">
            <div *ngIf="bid.hasError('required')">Bid is required.</div>
            <div *ngIf="bid.hasError('toolow')">
              Bid is too low, expect {{bid.errors.toolow.expected}}, current value is 
              {{bid.value}}.
            </div>
          </div>
       </form>
    </div>
    <hr>
    <button (click)="post()" [disabled]="form.invalid">POST BID</button>
  `,
  styles: [`
    input.ng-invalid.ng-touched {
      border-left: 5px solid red;
    }
    
    input.ng-valid.ng-touched {
      border-left: 5px solid forestgreen;
    }
  `]
})
export class AppComponent implements OnInit{
  bids: Bid[];

  form = new FormGroup({
    name: new FormControl('', Validators.required),
    bid: new FormControl('', Validators.required, this.minimumBid.bind(this))
  });

  constructor(
    private _http: Http, 
    @Inject('config')private config) {
  }

  ngOnInit() {
    this._http.get(`${this.config.databaseURL}/bids`)
      .map(resp => resp.json())
      .subscribe( res => this.bids = res)
  }

 // 異步驗(yàn)證器
  minimumBid(ctrl: AbstractControl): Observable<ValidationErrors|null> {
    return this._http.get(`${this.config.databaseURL}/bids`)
      .map(resp => resp.json())
      .map(bids => bids[bids.length - 1])
      .map(bid => {
        return ctrl.value > bid.bid ? null : {toolow: {expected: bid.bid}}
      });
  }

  get name() { return this.form.get('name'); }

  get bid() { return this.form.get('bid'); }

 // 新增Bid
  post() {
    let newBid = {...this.form.value, id: ++this.bids[this.bids.length - 1].id};
    this._http.post(`${this.config.databaseURL}/bids`, newBid)
      .map(resp => resp.json())
      .subscribe(resp => {
        this.bids.push(resp);
      });
    this.form.reset();
  }
}

第三節(jié) - 即將到來(lái)的驗(yàn)證功能

驗(yàn)證流程

validation-process

流程一

validation-process-1

流程二

validation-process-2

驗(yàn)證管線

validation-pipeline

基于上面的內(nèi)容我們能做什么

  • 定制驗(yàn)證器鏈
  • 控制驗(yàn)證順序和驗(yàn)證時(shí)間
  • 當(dāng)應(yīng)用程序出現(xiàn)錯(cuò)誤時(shí),發(fā)出錯(cuò)誤信息
  • 基于 Push 驗(yàn)證

定制驗(yàn)證器鏈?zhǔn)纠?/h4>
// ValidatorChain 目前還不支持
export class AppComponent implements OnInit{
  bids: Bid[];

  form = new FormGroup({
    name: new FormControl('', Validators.required),
    bid: new FormControl('', {chain: this.myChain.bind(this)})
  });

  myChain(ctrl: AbstractControl): ValidatorChain {
    return (obs) => {
        return obs.map(Validators.required)
          .switchMap(errs => errs ? Observable.of(errs) : 
            this.minimumBid(ctrl)).startWith(PENDING)
  }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,695評(píng)論 19 139
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,351評(píng)論 25 708
  • 月灑金江映金月,元魂飛入蓬萊河,千年大椿萬(wàn)載松,莫如南極獸頭血。九天玉京出老仙,三山福地納圣賢,明堂關(guān)元搬河車,繁...
    李一云閱讀 244評(píng)論 4 0
  • 最近和兒子倆人在較量,對(duì)上了,就差干上了(*?????)。還沒(méi)十五六歲呢,兒子就差點(diǎn)養(yǎng)成仇人,閨女還沒(méi)有(...
    我的ID是長(zhǎng)興小堂客閱讀 400評(píng)論 0 0
  • 我終于將戴了三年的碧玉珠取了下來(lái),轉(zhuǎn)身?yè)Q上了一根純金項(xiàng)鏈,墜子也是金的??粗R子里畫(huà)風(fēng)陡轉(zhuǎn)的人,陌生到想要落淚。 ...
    繹如閱讀 289評(píng)論 0 2

友情鏈接更多精彩內(nèi)容