Forms 角度2-警告/提示的表单验证

Forms 角度2-警告/提示的表单验证,forms,validation,angular,Forms,Validation,Angular,我正在尝试添加不会使表单无效的表单验证。验证应仅显示为警告 例如,年龄验证。年龄大于90表示警告,年龄大于120表示错误 我在表单上尝试了两个FormGroup,在输入字段上尝试了两个[formControl]。仅使用第一个[formControl] 这种验证是否可以使用Angulars表单验证?哪种方法是正确的选择?我可能会这样做 <form #form="ngForm" (ngSubmit)="save()"> <input formControlName="cont

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

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

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


这种验证是否可以使用Angulars表单验证?哪种方法是正确的选择?

我可能会这样做

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

警告:年龄限制很高。。
错误:超出了年龄限制。。
正常

通过angular.io可以很容易地进行表单验证,提示您可以在其上阅读文档

但我的脑海中可能有类似的方法可以更好地帮助你

首先,我们创建一个名为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(); //
    }

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

}
首先,我们应该为反应式表单注入FormBuilder(不要忘记在主模块中导入反应式FormModule),然后在[buildForm()]方法中,我们在表单属性上构建一组表单,该属性是从抽象类表单继承的

然后在下一步中,我们创建一个订阅表单值更改,并在值更改时调用[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>

希望我能帮上忙。

我通过创建自定义验证器实现了这一点,它总是返回
null
。此外,此验证器还会创建其他属性
警告
。然后从您的视图中简单地检查这个属性

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");
  }
}
导出接口AbstractControlWarn扩展AbstractControl{warnings:any;}
导出函数tooBigAgeWarning(c:AbstractControlWarn){
如果(!c.value){返回null;}
设val=+c.value;
c、 warnings=val>90&&val 120?{impossibleAge:{val}}}:null;
}
@组成部分({
选择器:“我的应用程序”,
模板:`
年龄:
错误!年龄是必需的
错误!年龄大于120
警告!年龄大于90岁
发送
`,
})
导出类应用程序{
年龄:对照组;
构造函数(私有_fb:FormBuilder){}
恩戈尼尼特(){
this.form=this.\u fb.group({
年龄:[''[
需要验证器,
tooBigAgeWarning,
不可能验证程序]]
})
this.age=this.form.get(“age”);
}
}
示例:

接受的答案在开发模式下工作得非常完美,但如果您尝试在--prod模式下构建,则会出现此错误

...  Property 'warnings' does not exist on type 'FormControl'.
为了修复这个错误,我对原始代码(App类)进行了调整,基本上是为了修复松散类型的变量。这是新版本:

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])
        });       
      }
    }
导出类FormControlWarn扩展FormControl{warnings:any;}
导出函数tooBigAgeWarning(c:FormControlWarn){
如果(!c.value){返回null;}
设val=+c.value;
c、 warnings=val>90&&val 120?{impossibleAge:{val}}}:null;
}
@组成部分({
选择器:“我的应用程序”,
模板:`
年龄:
错误!年龄是必需的
错误!年龄大于120
警告!年龄大于90岁
发送
`,
})
导出类应用程序{
获取年龄():FormControlWarn{
返回此.form.get(“年龄”);
}
构造函数(私有_fb:FormBuilder){}
恩戈尼尼特(){
this.form=this.\u fb.group({
年龄:新FormControlWarn(“”[
需要验证器,
tooBigAgeWarning,
不可能验证程序])
});       
}
}

感谢您的回复!这是一个很好的解决方案,但我使用的是一个更通用的解决方案,其中表单字段和验证是动态生成的,因此我无法硬编码验证。感谢您花时间阅读详细文章,但我没有看到在一个字段上有两个不同的验证,其中第一个会产生错误并使验证无效窗体,另一个仅显示警告。请参见“年龄”字段中的“我的描述”。我想在一个字段上添加两个Validator.minLength。明白了,您的问题可以通过自定义验证来解决;我将更新答案。我已将以下输出添加到您的form.component.html{{{form.controls.age.valid}{{form.valid}}。表单和字段也在91上。其思想是告诉自定义验证不应使表单无效,但仍应添加消息?在该策略中,基于验证错误添加消息还包括hasError()方法给出的表单和字段有效属性,这意味着如果存在错误,则字段和表单无效。因此,您的问题无法通过此策略解决。(我认为您的问题需要在angular2 AbstractControl中进行一些编辑。)好的简单解决方案!非常感谢。嘿快速提问如果我们已经使用了ngIf,为什么需要
[hidden]=“age.pristine”
?那太棒了!!很高兴我找到了这个答案,谢谢!
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])
        });       
      }
    }