ng-conf-2017 - Angular Form Validation

YouTube 地址:ng-conf-2017 - Angular Form Validation
Google Doc:PPTgit

目錄

  • 第一節 - 驗證概述github

  • 第二節 - 設置基本的驗證typescript

  • 第三節 - 即將到來的驗證功能shell

第一節 - 驗證概述

overview-form-control

同步驗證器

validator-fn

同步驗證器函數

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

異步驗證器

async-validator-fn

異步驗證器函數

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

第二節 - 設置基本的驗證

json-server 簡介

json-server 用於基於 JSON 數據快速地建立本地模擬的 REST API。npm

json-server 的安裝

$ npm install -g json-server

json-server 的使用

$ json-server --watch bids.json

Angular CLI 代理配置

建立 proxy.conf.json 文件

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

更新 package.json 文件

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

建立 bids.json 文件

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

同步驗證與異步驗證示例

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)
  }

 // 異步驗證器
  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();
  }
}

第三節 - 即將到來的驗證功能

驗證流程

validation-process

流程一

validation-process-1

流程二

validation-process-2

驗證管線

validation-pipeline

基於上面的內容咱們能作什麼

  • 定製驗證器鏈json

  • 控制驗證順序和驗證時間bootstrap

  • 當應用程序出現錯誤時,發出錯誤信息app

  • 基於 Push 驗證異步

定製驗證器鏈示例

// 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)
  }
}
相關文章
相關標籤/搜索