Angular 2 - 警告/提示的表单验证

时间:2016-10-28 15:19:12

标签: forms validation angular

我试图添加不会使表单无效的表单验证。验证应仅显示为警告。

E.g。年龄验证。年龄大于90表示警告,年龄大于120表示错误。

我已尝试在表单上使用两个FormGroup,在输入字段上使用两个[formControl]。只使用了第一个[formControl]。

是否可以使用Angulars表单验证进行此类验证?哪种方法可行?

4 个答案:

答案 0 :(得分:16)

我是通过创建自定义验证程序来完成的,它始终返回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

答案 1 :(得分: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。 / p>

然后在接下来我们创建表单值更改的订阅,并且在值更改时我们调用[onValueChanged()]方法。

在[onValueChanged()]方法中我们检查表单的字段是否有效,如果不是,我们从protected 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>

模板非常简单,内部检查字段是否有错误,如果有错误绑定。

对于bootstrap,您可以执行下面的其他操作

<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的可选参数,这个参数会导致您指定多个类似的验证,如示例中的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 !!!'
    }
}

希望我帮助过。

答案 2 :(得分:1)

Sergey Voronezhskiy可接受的答案在开发模式下是完美的,但是如果您尝试在--prod模式下进行构建,则会出现此错误。

...  Property 'warnings' does not exist on type 'FormControl'.

为了解决此错误,我对原始代码进行了调整,基本上是为了修复松散类型的变量,这是新版本:

export class FormControlWarn extends FormControl { warnings: any; }

export function tooBigAgeWarning(c: FormControlWarn ) {
    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 {
      get age(): FormControlWarn{
         return <FormControlWarn>this.form.get("age");
      }
      constructor(private _fb: FormBuilder) { }
      ngOnInit() {
        this.form = this._fb.group({
          age: new FormControlWarn('', [
            Validators.required,
            tooBigAgeWarning,
            impossibleAgeValidator])
        });       
      }
    }

答案 3 :(得分: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>