首页 文章

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

提问于
浏览
10

我正在尝试添加不会使表单无效的表单验证 . 验证应仅显示为警告 .

例如 . 年龄验证 . 年龄大于90表示警告,年龄大于120表示错误 .

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

是否可以使用Angulars表单验证进行此类验证?要走哪条路?

4 回答

  • 15

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

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

    UPDATE: 我试图为你创建一个非常简单但几乎完整的样本,你当然可以开发更狂野的规模: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 !!!'
        }
    }
    

    希望我帮忙 .

  • 0

    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])
            });       
          }
        }
    
  • 1

    这可能就是我如何做到的 .

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

相关问题