【问题标题】:Min / Max Validator in Angular 2 FinalAngular 2 Final 中的最小/最大验证器
【发布时间】:2017-02-12 08:35:04
【问题描述】:

根据thoughtgram.io,目前支持的验证器有:

  • 需要
  • 最小长度
  • 最大长度
  • 模式

因此,考虑以下代码 (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"

那么,要让表单在 firstValue ngModel

【问题讨论】:

  • FirstValue &lt; 0&lt;input ngModel="firstValue" min="0"。表单状态:VALID。我是否真的需要构建一个自定义验证器来确保表单状态:INVALID 当模型超出min / max 值的范围时,或者是否有 NG2 本身支持的东西?
  • 是的,你需要。在此处查看源代码:github.com/angular/angular/blob/master/modules/%40angular/forms/… 只有 thinkram 文章中提到的这 4 个验证器才支持 OOTB。

标签: validation angular typescript angular2-forms


【解决方案1】:

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

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

  • 必填
  • 需要True
  • 最小长度
  • 最大长度
  • 模式
  • nullValidator
  • 撰写
  • composeAsync

验证器: 这是我的号码验证器的低调版本,您可以根据需要改进它

static number(prms = {}): ValidatorFn {
    return (control: FormControl): {[key: string]: any} => {
      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}))

【讨论】:

  • 为什么 Angular 2 不支持内置的 min/max 输入属性?这是非常不直观的
  • @Blauhirn 不知道,可能编写验证器的人在中途感到无聊:)
  • Angular 4 现在支持最小/最大验证器。 angular.io/api/forms/Validators
  • @Olezt,Angular 4 现在只支持最小/最大验证器作为函数而不是指令,这意味着它们在模板驱动的表单中完全没用。这是一个非常奇怪的决定。
  • @Senthe 最初添加了对模板驱动表单的支持,但这是一个重大更改(因此 rolled back),因为许多人已经在使用 minmax,但并非所有人都在使用期待它的验证。有this request,但它的范围更大,可能会更慢,所以我刚刚添加了a more tailored request
【解决方案2】:

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

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

【讨论】:

  • 仅链接的答案是not useful
  • 嗯,这对我很有用!
  • 当心:我的应用程序的 AOT 版本似乎存在问题。
  • @KumarSaurabh 同意,最好包含答案的基本部分 - 但您的评论将此标记为“建议删除?”
  • 这个链接很有用。但是,从技术上讲,它是一个仅限链接的答案,因此我进行了编辑以包含一个小解释和一个示例。
【解决方案3】:

您可以通过创建实现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



  }

}

【讨论】:

【解决方案4】:

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

Angular 默认提供以下验证器。在此处添加列表,以便新手可以轻松了解当前支持的默认验证器是什么,并根据他们的兴趣进一步搜索。

  • 分钟
  • 最大
  • 必填
  • 需要True
  • 电子邮件
  • 最小长度
  • 最大长度
  • 模式
  • nullValidator
  • 撰写
  • composeAsync

您将获得完整列表Angular validators

如何使用最小/最大验证器: 来自 Angular 的文档 -

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

min()/ma​​x()接受数字参数的静态函数>返回 一个验证器函数,它返回带有 min/ma​​x 属性的错误映射 如果验证检查失败,否则为null。

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

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

在 formControl 中使用 ma​​x 验证器,(更多信息,click here

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

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

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

【讨论】:

    【解决方案5】:

    我现在也在找同样的东西,用this解决了。

    我的代码:

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

    【讨论】:

    • 需要注意的是,Validators 上的 min() 和 max() 函数只存在于最新 Angular 8 的 angular/forms 上。
    • min() 和 max() 作为函数而不是指令存在
    • 这是针对反应式表单的解决方案,而不是模板驱动的表单。
    【解决方案6】:

    据我所知,现在有没有实现,查看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;
        };
      }
    

    【讨论】:

    • 验证 logic 存在于 Angular 中,但他们没有将其作为指令公开。所以任何做模板驱动表单的人仍然需要编写自己的指令(如@amd 的答案所示),或者使用库。
    【解决方案7】:

    显然,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】:
      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>
        

      【讨论】:

      • 在您需要连接disabled 之前,它们会更好,此时您会发现要使其正常工作非常麻烦。您最终不得不创建各种复杂的订阅、设置访问器和更改检测器,只是为了动态禁用您的表单。可怕的是,Angular 决定放弃在反应式表单控件中为 disable 初始化提供函数的能力。
      【解决方案9】:

      我发现这是一个解决方案。如下创建一个自定义验证器

      minMax(control: FormControl) {
            return parseInt(control.value) > 0 && parseInt(control.value) <=5 ? null : {
              minMax: true
            }
        }
      

      在构造函数下包含以下代码

      this.customForm= _builder.group({
                        'number': [null, Validators.compose([Validators.required, this.minMax])],
                      });
      

      其中 customForm 是 FormGroup 而 _builder 是 FormBuilder。

      【讨论】:

        【解决方案10】:

        Angular 6 支持 minma​​x 验证器:https://angular.io/api/forms/Validators

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

        静态:

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

        动态:

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

        【讨论】:

        • @sumitkanoje 在 Angular 5 中,以下内容以模板驱动形式为我工作:this.templateItem1 = new FormControl('', [ Validators.required, Validators.pattern('[0-9]+'), Validators.min(1), Validators.max(10) ]); 对于必需的输入字段,仅允许数字,并且必须在 [1-10 ]。在 HTML 中,元素是:&lt;input type="text" class="form-control" id="item1" formControlName="templateItem1"&gt;(并且存在于 form-groupform 元素中),然后您可以使用 form-control-feedbacktemplateItem1.errors .dirty .touched 来获取验证消息。
        • 它不是模板驱动的表单
        • 来自有关 min 和 max 的 Angular 文档:“验证器仅作为函数存在,而不作为指令存在。”最小值最大值仅适用于反应形式。
        【解决方案11】:

        Angular 有 minmax 验证器,但仅适用于响应式表单。正如它在文档中所说:“验证器仅作为函数存在,而不是作为指令存在。”

        为了能够在模板驱动的表单中使用这些验证器,您需要创建自定义指令。在我的实现中,我使用@HostBinding 来应用 HTML min/max-attributes。我的selectors 也非常具体,以防止在自定义表单控件上运行验证,这些控件使用ControlValueAccessor 实现minmax 输入(例如MatDatePickerInput

        最小验证器:

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

        最大验证器:

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

        【讨论】:

          【解决方案12】:

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

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

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

          年龄总是在 1 到 18 岁之间。

          【讨论】:

            【解决方案13】:

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

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

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

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

              quantityFormControl = new FormControl();
            
            OnProductSelected(){
                this.quantityFormControl.setValidators(Validators.max(this.someVariable));
              }
            

            希望对你有帮助。

            【讨论】:

              【解决方案14】:

              在我的模板驱动表单(Angular 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】:

                找到用于最小值验证的自定义验证器。我们指令的选择器名称是 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;
                  }
                } 
                

                我们可以将 customMaxformControlNameformControlngModel 属性一起使用。

                在模板驱动表单中使用自定义最小值和最大值验证器

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

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

                【讨论】:

                • 这对我有用,但你应该编辑指令以转换为数字,因为它正在与 "v > this.customMax" 到 "v > +this.customMax" 中的字符串进行比较,因为它不起作用在角度 7
                • 这可能是因为输入类型可能等于文本而不是数字。因此,您可以转换为数字或将类型更改为数字
                【解决方案16】:

                我的严格编译器版本

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

                【讨论】:

                  【解决方案17】:

                  使用

                  Validators.min(5)
                  

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

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

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

                  中可用

                  【讨论】:

                    【解决方案18】:

                    我在 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)
                      }
                    }
                    

                    【讨论】:

                      【解决方案19】:

                      这个问题已经回答了。我想从@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);
                          }
                      
                      }
                      

                      【讨论】:

                        【解决方案20】:

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

                        【讨论】:

                        • 问题是关于 NG2 验证如何支持 minlength 而 min 不支持,如果这是有意的,开箱即用的东西 - 或者只是我缺少的一些 NG 知识。我知道 min 和 minlength 之间的区别:P
                        猜你喜欢
                        • 1970-01-01
                        • 2017-04-02
                        • 1970-01-01
                        • 1970-01-01
                        • 2018-04-08
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多