2016-10-28 27 views
6

我想添加表單驗證,不會使表單失效。驗證應該只顯示爲警告。Angular 2 - 表單驗證的警告/提示

E.g.年齡驗證。年齡大於90表示警告,年齡大於120表示錯誤。

我已經嘗試了兩個formGroups的形式和兩個[formControl] s的輸入字段。只有第一個[formControl]被使用。

是否可以使用Angulars表單驗證進行這種驗證?哪種方法是可行的?

回答

10

我已經通過創建自定義驗證程序來完成它,它總是返回null。此驗證器也創建附加屬性warnings。然後只需從您的視圖中檢查此屬性。

export interface AbstractControlWarn extends AbstractControl { warnings: any; } 

export function tooBigAgeWarning(c: AbstractControlWarn) { 
    if (!c.value) { return null; } 
    let val = +c.value; 
    c.warnings = val > 90 && val <= 120 ? { tooBigAge: {val} } : null; 
    return null; 
} 

export function impossibleAgeValidator(c: AbstractControl) { 
    if (tooBigAgeWarning(c) !== null) { return null; } 
    let val = +c.value; 
    return val > 120 ? { impossibleAge: {val} } : null; 
} 

@Component({ 
    selector: 'my-app', 
    template: ` 
    <div [formGroup]="form"> 
     Age: <input formControlName="age"/> 
     <div *ngIf="age.errors?.required" [hidden]="age.pristine"> 
     Error! Age is required 
     </div> 
     <div *ngIf="age.errors?.impossibleAge" [hidden]="age.pristine"> 
     Error! Age is greater then 120 
     </div> 
     <div *ngIf="age.warnings?.tooBigAge" [hidden]="age.pristine"> 
     Warning! Age is greater then 90 
     </div> 
     <p><button type=button [disabled]="!form.valid">Send</button> 
    </div> 
    `, 
}) 
export class App { 
    age: FormControl; 
    constructor(private _fb: FormBuilder) { } 
    ngOnInit() { 
    this.form = this._fb.group({ 
     age: ['', [ 
     Validators.required, 
     tooBigAgeWarning, 
     impossibleAgeValidator]] 
    }) 
    this.age = this.form.get("age"); 
    } 
} 

例子:https://plnkr.co/edit/me0pHePkcM5xPQ7nzJwZ?p=preview

+0

好的和簡單的解決方案!謝謝! – meleagros

0

這可能是我如何做到的。

<form #form="ngForm" (ngSubmit)="save()"> 

    <input formControlName="controlName"> 

    <span *ngIf="form.pristine && form.controls.controlName.value > 90 && form.controls.controlName.value < 120"> 
    Warning: Age limit is high.. 
    </span> 

    <span *ngIf="form.pristine && form.controls.controlName.value > 120"> 
    Error: Age limit exceeded.. 
    </span> 

<form> 
+0

感謝您的答覆!它是一個很好的解決方案,但我使用更通用的解決方案,其中表單字段和驗證是動態生成的,因此我無法對驗證進行硬編碼。 – meleagros

1

其可以通過angular.io容易表單驗證暗示你可以https://angular.io/docs/ts/latest/cookbook/form-validation.html

但類似的方式,可以幫助你更好地可能在我的腦海裏讀取文件。

首先我們創建一個名爲Form的抽象類,它包含一些常用的函數和屬性。

import {FormGroup} from "@angular/forms"; 

export abstract class Form { 
    form: FormGroup; 

    protected abstract formErrors: Object; 

    protected abstract validationMessages: Object; 

    onValueChanged(data?: any) { 
     if (!this.form) { return; } 
     const form = this.form; 

     for (const field in this.formErrors) { 
      this.formErrors[field] = ''; 
      const control = form.get(field); 

      if (control && control.dirty && !control.valid) { 
       const messages = this.validationMessages[field]; 

       for (const key in control.errors) { 
        this.formErrors[field] = messages[key]; 
        break; 
       } 
      } 
     } 
    } 
} 

,那麼你應該創建一個名爲LoginComponent例如表單組件像下面

import {Component, OnInit} from "@angular/core"; 
import {Form} from "./form"; 
import {Validators, FormBuilder} from "@angular/forms"; 


@Component({ 
    templateUrl: '...' 
}) 
export class LoginComponent extends Form implements OnInit { 

    protected formErrors = { 
     'email': '', 
     'password': '' 
    } 

    protected validationMessages = { 
     'email': { 
      'required': 'email required message', 
      'email': 'email validation message' 
     }, 
     'password': { 
      'required': 'password required message', 
      'minlength': 'password min length message', 
      'maxlength': 'password max length message', 
     } 
    } 

    constructor(private _fb: FormBuilder) { } 

    ngOnInit() { 
     this.buildForm(); 
    } 

    buildForm() { 
     this.form = this._fb.group({ 
      'email': ['', [ 
       Validators.required, 
       // emailValidator 
      ]], 
      'password': ['', [ 
       Validators.required, 
       Validators.minLength(8), 
       Validators.maxLength(30) 
      ]] 
     }); 

     this.form.valueChanges 
      .subscribe(data => this.onValueChanged(data)); 

     this.onValueChanged(); // 
    } 

} 

首先要注入FormBuilder無功表(不要忘了你的主模塊中導入ReactiveFormModule),然後在[buildForm()]方法中,我們在窗體屬性上構建了一組窗體,該窗體屬性從抽象類Form繼承。

然後在接下來我們創建一個訂閱表單值的更改,並在值更改時調用[onValueChanged()]方法。

在[onValueChanged()]方法中,我們檢查表單的字段是否有效,如果沒有,我們從受保護的validationMessages屬性獲取消息並在formErrors屬性中顯示它。

那麼你的模板應該是類似這樣

<div class="col-md-4 col-md-offset-4"> 
    <form [formGroup]="form" novalidate> 


     <div class="form-group"> 
      <label class="control-label" for="email">email</label> 
      <input type="email" formControlName="email" id="email" class="form-control" required> 
      <div class="help help-block" *ngIf="formErrors.email"> 
       <p>{{ formErrors.email }}</p> 
      </div> 
     </div> 

     <div class="form-group"> 
      <label class="control-label" for="password">password</label> 
      <input type="password" formControlName="password" id="password" class="form-control" required> 
      <div class="help help-block" *ngIf="formErrors.password"> 
       <p>{{ formErrors.password }}</p> 
      </div> 
     </div> 

     <div class="form-group"> 
      <button type="submit" class="btn btn-block btn-primary" [disabled]="!form.valid">login</button> 
     </div> 
    </form> 
</div> 

模板是很容易的,你內心檢查現場有錯誤或不如果有錯誤的綁定。

爲引導,你可以做別的事情像下面

<div class="form-group" [ngClass]="{'has-error': form.controls['email'].dirty && !form.controls['email'].valid, 'has-success': form.controls['email'].valid}"> 
    <label class="control-label" for="email">email</label> 
    <input type="email" 
      formControlName="email" 
      id="email" 
      class="form-control" 
      required> 
    <div class="help help-block" *ngIf="formErrors.email"> 
     <p>{{ formErrors.email }}</p> 
    </div> 
</div> 

更新:我試圖創建一個非常簡單的,但幾乎完全樣品你當然可以開發它狂野規模: https://embed.plnkr.co/ExRUOtSrJV9VQfsRfkkJ/

但有一點描述,你可以創建一個像下面這樣的自定義驗證

import {ValidatorFn, AbstractControl} from '@angular/forms'; 

function isEmptyInputValue(value: any) { 
    return value == null || typeof value === 'string' && value.length === 0; 
} 

export class MQValidators { 

    static age(max: number, validatorName: string = 'age'): ValidatorFn { 
    return (control: AbstractControl): {[key: string]: any} => { 
     if (isEmptyInputValue(control.value)) return null; 

     const value = typeof control.value == 'number' ? control.value : parseInt(control.value); 

     if (isNaN(value)) return null; 

     if (value <= max) return null; 

     let result = {}; 
     result[validatorName] = {valid: false}; 

     return result; 
    } 
    } 

} 

這個自定義的驗證獲得命名validatorName一個可選PARAM,這PARAM因爲你指定多類似的驗證作爲您的示例formComponent應該有如下:

buildForm() { 

    this.form = this._fb.group({ 
     'age': ['', [ 
      Validators.required, 
      Validators.pattern('[0-9]*'), 
      MQValidators.age(90, 'abnormalAge'), 
      MQValidators.age(120, 'incredibleAge') 
     ]] 
    }); 

    this.form.valueChanges 
     .subscribe(data => this.onValueChanged(data)); 

    this.onValueChanged(); 
} 

onValueChanged(data?: any): void { 
    if (!this.form) { return; } 
    const form = this.form; 

    for (const field in this.formErrors) { 
     this.formErrors[field] = ''; 
     const control = form.get(field); 

     if (control && control.dirty && !control.valid) { 
      const messages = this.validationMessages[field]; 

      for (const key in control.errors) { 
       this.formErrors[field] = messages[key]; 
      } 
     } 
    } 
} 

formErrors = { 
    age: '' 
} 

validationMessages = { 
    'age': { 
     'required': 'age is required.', 
     'pattern': 'age should be integer.', 
     'abnormalAge': 'age higher than 90 is abnormal !!!', 
     'incredibleAge': 'age higher than 120 is incredible !!!' 
    } 
} 

希望我幫助。

+0

感謝您抽出時間閱讀詳細信息,但是我沒有看到在第一個產生錯誤並使表單失效並且另一個只顯示警告的字段中有兩個不同驗證的部分。看到我的描述與年齡字段。我想在一個字段上添加兩個Validators.minLength。 – meleagros

+0

明白了,您的問題可以通過自定義驗證來解決;我會更新答案。 –

+0

我已將以下輸出添加到您的form.component.html {{form.controls.age.valid}} {{form.valid}}。表格和字段也是無效的。這個想法是告訴自定義驗證它不應該使窗體無效,但仍然要添加一條消息? – meleagros