Angular 2 Final中的最小/最大验证器

时间:2016-10-04 08:44:21

标签: validation angular typescript angular2-forms

根据thoughtgram.io,目前支持的验证人是:

  • 需要
  • MINLENGTH个
  • 的maxlength
  • 图案

因此,考虑以下代码(plunkr here):

@Component({
  selector: 'my-app',
  template: `

  <form #formRef="ngForm">
    <input type="number" [(ngModel)]="firstValue" name="firstValue" min="0" required/>
    <input type="text" [(ngModel)]="secondValue" maxlength="5" name="secondValue" required/>
    <button type="submit"> Submit </button> 
  </form>

  FORM: {{formRef.form | json }}
`
})
export class AppComponent { 
  firstValue = -22;
  secondValue = "eyy macarena!"; 
}

虽然支持minlength,但角度验证会忽略min="0"

enter image description here

enter image description here

因此,当firstValue ngModel&lt;时,使表单导致错误。 0,我是否需要构建自定义验证器?

19 个答案:

答案 0 :(得分:43)

要在min/max validation上应用number,您需要创建Custom Validator

Validators类目前只有几个验证器,即

  • 必需
  • requiredTrue
  • MINLENGTH个
  • 最大长度
  • 图案
  • nullValidator
  • 撰写
  • composeAsync

验证码: 以下是我的号码验证器的简化版本,您可以随意改进

static number(prms = {}): ValidatorFn {
    return (control: FormControl): {[key: string]: string} => {
      if(isPresent(Validators.required(control))) {
        return null;
      }

      let val: number = control.value;

      if(isNaN(val) || /\D/.test(val.toString())) {

        return {"number": true};
      } else if(!isNaN(prms.min) && !isNaN(prms.max)) {

        return val < prms.min || val > prms.max ? {"number": true} : null;
      } else if(!isNaN(prms.min)) {

        return val < prms.min ? {"number": true} : null;
      } else if(!isNaN(prms.max)) {

        return val > prms.max ? {"number": true} : null;
      } else {

        return null;
      }
    };
  }

用法:

// check for valid number
var numberControl = new FormControl("", [Validators.required, CustomValidators.number()])

// check for valid number and min value  
var numberControl = new FormControl("", CustomValidators.number({min: 0}))

// check for valid number and max value
var numberControl = new FormControl("", CustomValidators.number({max: 20}))

// check for valid number and value range ie: [0-20]
var numberControl = new FormControl("", CustomValidators.number({min: 0, max: 20}))

答案 1 :(得分:28)

我找到了一个实现了很多自定义验证器的库 - ng2-validation - 可以与模板驱动的表单(属性指令)一起使用。例如:

<input type="number" [(ngModel)]="someNumber" name="someNumber" #field="ngModel" [range]="[10, 20]"/>
<p *ngIf="someNumber.errors?.range">Must be in range</p>

答案 2 :(得分:10)

您可以通过创建实现Validator接口的指令轻松实现自己的验证(模板驱动)。

import { Directive, Input, forwardRef } from '@angular/core'
import { NG_VALIDATORS, Validator, AbstractControl, Validators } from '@angular/forms'

@Directive({
  selector: '[min]',
  providers: [{ provide: NG_VALIDATORS, useExisting: MinDirective, multi: true }]
})
export class MinDirective implements Validator {

  @Input() min: number;

  validate(control: AbstractControl): { [key: string]: any } {

    return Validators.min(this.min)(control)

    // or you can write your own validation e.g.
    // return control.value < this.min ? { min:{ invalid: true, actual: control.value }} : null



  }

}

答案 3 :(得分:9)

据我所知,现在是否已实施,请检查https://github.com/angular/angular/blob/master/packages/forms/src/validators.ts

这是实现您所需要的部分:

 export class Validators {
  /**
   * Validator that requires controls to have a value greater than a number.
   */
  static min(min: number): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
      if (isEmptyInputValue(control.value) || isEmptyInputValue(min)) {
        return null;  // don't validate empty values to allow optional controls
      }
      const value = parseFloat(control.value);
      // Controls with NaN values after parsing should be treated as not having a
      // minimum, per the HTML forms spec: https://www.w3.org/TR/html5/forms.html#attr-input-min
      return !isNaN(value) && value < min ? {'min': {'min': min, 'actual': control.value}} : null;
    };
  }

  /**
   * Validator that requires controls to have a value less than a number.
   */
  static max(max: number): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
      if (isEmptyInputValue(control.value) || isEmptyInputValue(max)) {
        return null;  // don't validate empty values to allow optional controls
      }
      const value = parseFloat(control.value);
      // Controls with NaN values after parsing should be treated as not having a
      // maximum, per the HTML forms spec: https://www.w3.org/TR/html5/forms.html#attr-input-max
      return !isNaN(value) && value > max ? {'max': {'max': max, 'actual': control.value}} : null;
    };
  }

答案 4 :(得分:7)

我现在正在寻找同一件事,使用this来解决。

我的代码:

this.formBuilder.group({
  'feild': [value,  [Validators.required, Validators.min(1)]]
});

答案 5 :(得分:5)

  1. 切换到使用反应形式而不是模板形式(它们只是更好),否则第5步将略有不同。
  2. 创建服务NumberValidatorsService并添加验证器函数:

    import { Injectable } from '@angular/core';
    import { FormControl,  ValidatorFn } from '@angular/forms';
    
    @Injectable()
    export class NumberValidatorsService {
    
     constructor() { }
    
      static max(max: number): ValidatorFn {
    return (control: FormControl): { [key: string]: boolean } | null => {
    
      let val: number = control.value;
    
      if (control.pristine || control.pristine) {
        return null;
      }
      if (val <= max) {
        return null;
      }
      return { 'max': true };
      }
    }
    
     static min(min: number): ValidatorFn {
    return (control: FormControl): { [key: string]: boolean } | null => {
    
      let val: number = control.value;
    
      if (control.pristine || control.pristine) {
        return null;
      }
      if (val >= min) {
        return null;
      }
      return { 'min': true };
      }
    }
    
    }
    
  3. 将服务导入模块。

  4. 在组件中添加包含语句的语句:

        import { NumberValidatorsService } from "app/common/number-validators.service";
    
  5. 将验证器添加到表单构建器:

        this.myForm = this.fb.group({
          numberInputName: [0, [Validators.required, NumberValidatorsService.max(100), NumberValidatorsService.min(0)]],
        });
    
  6. 在模板中,您可以按如下方式显示错误:

     <span *ngIf="myForm.get('numberInputName').errors.max">
             numberInputName cannot be more than 100. 
      </span>
    

答案 6 :(得分:4)

Angular 6 支持 min max 个验证器:https://angular.io/api/forms/Validators

您可以将其用于静态和动态值。

静态:

<input min="0" max="5">

动态:

<input [min]="someMinValue" [max]="someMaxValue">

答案 7 :(得分:3)

显然,Angular在某个时候具有模板驱动形式的max / min指令,但必须在v4.2.0中将其删除。您可以在此处阅读有关导致删除的回归的信息:https://github.com/angular/angular/issues/17491

目前,我所知道的唯一可行的解​​决方案是使用@amd建议的自定义指令。这是在Bootstrap 4中使用它的方法。

min-validator.directive.ts

import { Directive, Input } from '@angular/core'
import { NG_VALIDATORS, Validator, AbstractControl, Validators } from '@angular/forms'

@Directive({
  selector: '[min]',
  providers: [{ provide: NG_VALIDATORS, useExisting: MinDirective, multi: true }]
})
export class MinDirective implements Validator {

  @Input() min: number;

  validate(control: AbstractControl): { [key: string]: any } {    
    return Validators.min(this.min)(control)    
  }
}

在您的模板中:

<input type="number" [min]="minAge" #age="ngModel" [(ngModel)]="person.age" class="form-control" [ngClass]="{'is-invalid':age.invalid}">
<div *ngIf="age.invalid && (age.dirty || age.touched)" class="invalid-feedback">You need to be older than {{minAge}} to participate</div>

希望这会有所帮助!

答案 8 :(得分:2)

Angular具有minmax验证器,但仅适用于反应式窗体。就像在文档中说的那样:“验证器仅作为函数存在,而不作为指令存在。”

要能够以模板驱动的形式使用这些验证器,您需要创建自定义指令。在我的实现中,我使用@HostBinding来应用HTML min / max属性。我的selector也非常具体,可以防止验证在使用ControlValueAccessormin输入(例如MatDatePickerInput)实现max的自定义表单控件上运行 >

最小验证器:

import { Directive, HostBinding, Input } from '@angular/core';
import { AbstractControl, NG_VALIDATORS, ValidationErrors, Validator, Validators } from '@angular/forms';

@Directive({
  selector: 'input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]',
  providers: [{ provide: NG_VALIDATORS, useExisting: MinValidatorDirective, multi: true }]
})
export class MinValidatorDirective implements Validator {
  @HostBinding('attr.min') @Input() min: number;

  constructor() { }

  validate(control: AbstractControl): ValidationErrors | null {
    const validator = Validators.min(this.min);
    return validator(control);
  }
}

max-validator:

import { Directive, HostBinding, Input } from '@angular/core';
import { AbstractControl, NG_VALIDATORS, ValidationErrors, Validator, Validators } from '@angular/forms';

@Directive({
  selector: 'input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]',
  providers: [{ provide: NG_VALIDATORS, useExisting: MaxValidatorDirective, multi: true }]
})
export class MaxValidatorDirective implements Validator {
  @HostBinding('attr.max') @Input() max: number;

  constructor() { }

  validate(control: AbstractControl): ValidationErrors | null {
    const validator = Validators.max(this.max);
    return validator(control);
  }
}

答案 9 :(得分:1)

使用

Validators.min(5)

可以在与其他验证器一起创建formGroup变量时使用它,如

dueAmount: ['', [Validators.required, Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/), Validators.min(5)]]

不确定是否在 Angular 2 中,但在 Angular 5

中可用

答案 10 :(得分:1)

找到用于最小编号验证的自定义验证器。我们的指令的选择器名称为customMin。

custom-min-validator.directive.ts

import { Directive, Input } from '@angular/core';
import { NG_VALIDATORS, Validator, FormControl } from '@angular/forms';

@Directive({
  selector: '[customMin][formControlName],[customMin][formControl],[customMin][ngModel]',
  providers: [{provide: NG_VALIDATORS, useExisting: CustomMinDirective, multi: true}]
})
export class CustomMinDirective implements Validator {
  @Input()
  customMin: number;

  validate(c: FormControl): {[key: string]: any} {
      let v = c.value;
      return ( v < this.customMin)? {"customMin": true} : null;
  }
} 

找到用于最大数量验证的自定义验证器。我们的指令的选择器名称是customMax。

custom-max-validator.directive.ts

import { Directive, Input } from '@angular/core';
import { NG_VALIDATORS, Validator, FormControl } from '@angular/forms';

@Directive({
  selector: '[customMax][formControlName],[customMax][formControl],[customMax][ngModel]',
  providers: [{provide: NG_VALIDATORS, useExisting: CustomMaxDirective, multi: true}]
})
export class CustomMaxDirective implements Validator {
  @Input()
  customMax: number;

  validate(c: FormControl): {[key: string]: any} {
      let v = c.value;
      return ( v > this.customMax)? {"customMax": true} : null;
  }
} 

我们可以将 customMax formControlName formControl ngModel 属性一起使用。

以模板驱动的形式使用自定义最小和最大验证器

我们将以模板驱动的形式使用自定义的最小和最大验证器。对于最小数量验证,我们具有customMin属性,对于最大数量验证,我们具有customMax属性。现在,找到用于验证的代码段。

<input name="num1" [ngModel]="user.num1" customMin="15" #numberOne="ngModel">
<input name="num2" [ngModel]="user.num2" customMax="50"  #numberTwo="ngModel"> 

我们可以显示以下验证错误消息。

<div *ngIf="numberOne.errors?.customMin"> 
     Minimum required number is 15.
</div>  

<div *ngIf="numberTwo.errors?.customMax"> 
     Maximum number can be 50.
</div> 

要分配最小和最大数量,我们还可以使用物业出价。假设我们具有以下组件属性。

minNum = 15;
maxNum = 50; 

现在按如下所示对customMin和customMax使用属性绑定。

<input name="num1" [ngModel]="user.num1" [customMin]="minNum" #numberOne="ngModel">
<input name="num2" [ngModel]="user.num2" [customMax]="maxNum"  #numberTwo="ngModel"> 

答案 11 :(得分:1)

  

Angular现在默认支持最小/最大验证器。

Angular默认提供以下验证器。在此处添加列表,以便新用户可以轻松了解当前受支持的默认验证器,然后根据自己的兴趣在Google上进行进一步的搜索。

  • 分钟
  • 最大
  • 必填
  • 必需的真
  • 电子邮件
  • minLength
  • maxLength
  • 模式
  • nullValidator
  • 撰写
  • composeAsync

您将获得完整列表Angular validators

最小/最大验证器的使用方法: 从Angular的文档中-

static min(min: number): ValidatorFn 
static max(max: number): ValidatorFn 
  

min() / max() 接受数字参数 的静态函数> 返回   验证器函数 ,该函数返回具有 min / max 属性的错误映射   如果验证检查失败,则为null。

在formControl中使用 min 验证程序(有关更多信息,click here

const control = new FormControl(9, Validators.min(10));

在formControl中使用 max 验证器(有关更多信息,click here

const control = new FormControl(11, Validators.max(10));

有时我们需要动态添加验证器。 setValidators()是救星。您可以像下面这样使用它-

const control = new FormControl(10);
control.setValidators([Validators.min(9), Validators.max(11)]);

答案 12 :(得分:1)

在最新的Angular版本中,已经添加了min和max。链接在这里: https://angular.io/api/forms/Validators#max

这是我在项目中使用Max验证器的方式:

<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet" />

<!-- Bootstrap 4 Card -->
<div class="card" style="width: 18rem;">
  <div class="row no-gutters">
    <div class="col-6">
      <img class="w-100" src="https://via.placeholder.com/100" alt="Card image cap">
    </div>
    <div class="col-6">
      <img class="w-100" src="https://via.placeholder.com/100" alt="Card image cap">
    </div>
  </div>
  <div class="card-body">
    <h5 class="card-title">Card title</h5>
    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
    <a href="#" class="btn btn-primary">Go somewhere</a>
  </div>
</div>


<!-- Your code -->
<div class="d-flex align-items-stretch col-6 col-sm-6 col-md-4 col-lg-4 col-xl-4 p-2">
  <!-- Card -->
  <a href="https://www.example.com" class="card w-100 bg-white text-dark border-1 shadow-sm rounded-top rounded-bottom">

    <div class="card-header border-top-0 bg-white pb-0 pt-0 border-top px-0">
      <div class="row mx-0 px-0">
        <div class="col-6 bg-success p-0">
          <img src="http://res.cloudinary.com/braincloud/image/fetch/w_300,h_300,c_thumb,g_faces/http://www.example.com/wp-content/uploads/groupm-dominic-grainger-thumbnail-1024x576.jpg" class="w-100">
        </div>
        <div class="col-6 p-0">
          <img src="https://logo.clearbit.com/groupm.com" class="img-fluid w-100 logocenter"> </div>
      </div>
    </div>

    <!-- Title -->
    <div class="card-body pb-0 pt-2 mt-0">
      <p class="card-title pt-2 font-weight-normal">How Europe Can Hit Addressable Scale: Grainger, GroupM</p>
    </div>

    <!-- Date -->
    <div class="card-footer bg-white text-muted small pt-0 border-top-0">Dec 13, 2018</div>
  </a>
  <!-- end .card -->
</div>

初始化表单控件,然后在组件中添加验证器:

<mat-form-field class="globalInput">
          <input (change)="CalculateAmount()" matInput placeholder="Quantity" name="productQuantity" type="number" [formControl]="quantityFormControl">
        </mat-form-field>
        <mat-error *ngIf="quantityFormControl.hasError('max')">
          Only <strong>{{productQuantity}}</strong> available!
        </mat-error>

您还可以在这样的事件上动态设置验证器:

  quantityFormControl = new FormControl('', Validators.max(15));

希望有帮助。

答案 13 :(得分:0)

Angualr本身提供最小和最大数量验证功能。

示例-我们有一个类似于年龄范围的字段,然后查看验证的使用。

  age_range : ['',  Validators.min(1), Validators.max(18)]]

年龄始终在1到18之间。

答案 14 :(得分:0)

在我的模板驱动形式(角度6)中,我有以下解决方法:

 <div class='col-sm-2 form-group'>
            <label for='amount'>Amount</label>
            <input type='number' 
                   id='amount' 
                   name='amount' 
                   required 
                   [ngModel] = 1
                   [pattern] = "'^[1-9][0-9]*$'"
                   class='form-control' 
                   #amountInput='ngModel'/>
            <span class='text-danger' *ngIf="amountInput.touched && amountInput.invalid">
              <p *ngIf="amountInput.errors?.required">This field is <b>required</b>!</p>
              <p *ngIf="amountInput.errors?.pattern">This minimum amount is <b>1</b>!</p>
            </span>
        </div>

上面的许多示例都使用了指令和自定义类,它们可以以更复杂的形式更好地扩展,但是如果您要查找简单的数字最小值,请使用pattern作为指令,并对正数施加正则表达式限制仅数字。

答案 15 :(得分:0)

我为amd的好答案添加了max验证。

import { Directive, Input, forwardRef } from '@angular/core'
import { NG_VALIDATORS, Validator, AbstractControl, Validators } from '@angular/forms'

/*
 * This is a wrapper for [min] and [max], used to work with template driven forms
 */

@Directive({
  selector: '[min]',
  providers: [{ provide: NG_VALIDATORS, useExisting: MinNumberValidator, multi: true }]
})
export class MinNumberValidator implements Validator {

  @Input() min: number;

  validate(control: AbstractControl): { [key: string]: any } {
    return Validators.min(this.min)(control)
  }
}

@Directive({
  selector: '[max]',
  providers: [{ provide: NG_VALIDATORS, useExisting: MaxNumberValidator, multi: true }]
})
export class MaxNumberValidator implements Validator {

  @Input() max: number;

  validate(control: AbstractControl): { [key: string]: any } {
    return Validators.max(this.max)(control)
  }
}

答案 16 :(得分:0)

这个问题已经回答。我想扩展@amd的答案。有时您可能需要一个默认值。

例如,要针对特定​​值进行验证,我想提供以下内容-

<input integerMinValue="20" >

但是32位有符号整数的最小值是-2147483648。为了验证此值,我不喜欢提供它。我想写如下-

<input integerMinValue >

要实现此目的,您可以按如下所示编写指令

import {Directive, Input} from '@angular/core';
import {AbstractControl, NG_VALIDATORS, ValidationErrors, Validator, Validators} from '@angular/forms';

@Directive({
    selector: '[integerMinValue]',
    providers: [{provide: NG_VALIDATORS, useExisting: IntegerMinValidatorDirective, multi: true}]
})
export class IntegerMinValidatorDirective implements Validator {

    private minValue = -2147483648;

    @Input('integerMinValue') set min(value: number) {
        if (value) {
            this.minValue = +value;
        }
    }

    validate(control: AbstractControl): ValidationErrors | null {
        return Validators.min(this.minValue)(control);
    }

}

答案 17 :(得分:0)

我的严格编译器版本

import { Directive, Input } from '@angular/core';
import { AbstractControl, NG_VALIDATORS, ValidationErrors, Validator } from '@angular/forms';

@Directive({
  selector: '[appMinValidator]',
  providers: [{ provide: NG_VALIDATORS, useExisting: MinValidatorDirective, multi: true }]
})
export class MinValidatorDirective implements Validator {

  @Input()
  appMinValidator!: number;

  validate(control: AbstractControl): ValidationErrors | null {
    return (control.value as number < this.appMinValidator) ? { appMinValidator: true } : null;
  }

}

答案 18 :(得分:-3)

在您的代码中,您使用的是min而不是minlength。另请注意,这不会验证数字是否> 0但是它的长度。