65

According to thoughtgram.io, the currently supported validators are:

  • required
  • minlength
  • maxlength
  • pattern

So, considering the following code (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!"; } 

While minlength is supported, min="0" is ignored by angular validation:

enter image description here

enter image description here

So, to make the form result in an error when firstValue ngModel < 0, do I need to build a custom validator?

2
  • FirstValue < 0, and <input ngModel="firstValue" min="0". Form status: VALID. Do I really need to build a custom validator to make sure Form status: INVALID when model is out of range from min / max values, or is there something NG2 natively supports? Commented Oct 4, 2016 at 9:01
  • Yes you would need to. Check the source code here: github.com/angular/angular/blob/master/modules/%40angular/forms/… Only those 4 validators mentioned by thoughtram article are supported OOTB. Commented Oct 4, 2016 at 9:08

20 Answers 20

68

To apply min/max validation on a number you will need to create a Custom Validator

Validators class currently only have a few validators, namely

  • required
  • requiredTrue
  • minlength
  • maxlength
  • pattern
  • nullValidator
  • compose
  • composeAsync

Validator: Here is toned down version of my number Validator, you can improve it as you like

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

Usage:

// 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})) 
Sign up to request clarification or add additional context in comments.

6 Comments

why doesnt angular 2 simply support the built-in min/max properties of inputs?? this is highly unintuitive
@Blauhirn Don't know, probably the guy writing the validators got bored halfway through :)
Angular 4 now supports min/max validators. angular.io/api/forms/Validators
@Olezt, Angular 4 right now only supports min/max validators as functions and not as directives, which means they are completely useless in template-driven forms. This is a very weird decision.
@Senthe Support for template driven forms was added originally but it was a breaking change (and thus rolled back) as many people were already using min and max and not all of them were expecting validation from it. There is this request but it has a larger scope and may be slower to happen and so I added a more tailored request just now.
|
33

I found a library implementing a lot of custom validators - ng2-validation - that can be used with template-driven forms (attribute directives). Example:

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

7 Comments

Link-only answers are not useful.
Well it sure was useful for me!
Beware: it seems to present problems in the AOT version of my app.
@KumarSaurabh Agreed, it's better to include essential parts of the answer - but your review flagged this as "Recommend deletion?"
The link is very useful. However, it is technically a link-only answer, so I have edited to also include a small explanation and an example.
|
31

Angular now supports min/max validators by default.

Angular provides the following validators by default. Adding the list here so that new comers can easily get to know what are the current supported default validators and google it further as per their interest.

  • min
  • max
  • required
  • requiredTrue
  • email
  • minLength
  • maxLength
  • pattern
  • nullValidator
  • compose
  • composeAsync

you will get the complete list Angular validators

How to use min/max validator: From the documentation of Angular -

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

min()/max() is a static function that accepts a number parameter and returns A validator function that returns an error map with the min/max property if the validation check fails, otherwise null.

use min validator in formControl, (for further info, click here)

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

use max validator in formControl, (for further info, click here)

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

sometimes we need to add validator dynamically. setValidators() is the saviour. you can use it like the following -

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

Comments

24

You can implement your own validation (template driven) easily, by creating a directive that implements the Validator interface.

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

5 Comments

It will be more helpful if you explain like answer above stackoverflow.com/a/44722596/3898339
Exactly what I need when writng template driven forms!
With template driven forms this is the best solution. Created a stackblitz here: stackblitz.com/edit/angular-min-max-validation
N.B: you have to use brackets, as [min]="0" instead of min="0", because directive wants a number, not a string.
@amd how to call validate when min changes? Validate gets only called when control changes, but not the conditions.
13

I was looking for the same thing now, used this to solve it.

My code:

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

3 Comments

Should be noted, the min() and max() function on Validators only exists on angular/forms for the newest Angular 8.
min() and max() exist as functions not as a directive
That is a solution for reactive forms, not template driven forms.
11

As far as I know, is it implemented now, check https://github.com/angular/angular/blob/master/packages/forms/src/validators.ts

This is the part that implements what you are looking for:

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

1 Comment

The validation logic exists in Angular, but they haven't exposed it as directives. So anyone doing template-driven forms will still need to write their own directives (as shown in @amd's answer), or use a library.
11

Apparently, Angular had the max/min directives for template driven forms at some point but had to remove them in v4.2.0. You can read about the regression that caused the removal here: https://github.com/angular/angular/issues/17491

For now the only working solution that I know of is to use custom directive as @amd suggested. Here's how to use it with 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) } } 

And in your template:

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

Hope this helps!

Comments

6
  1. Switch to use reactive forms instead of template forms (they are just better), otherwise step 5 will be slightly different.
  2. Create a service NumberValidatorsService and add validator functions:

    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. Import service into module.

  4. Add includes statement in component where it is to be used:

     import { NumberValidatorsService } from "app/common/number-validators.service"; 
  5. Add validators to form builder:

     this.myForm = this.fb.group({ numberInputName: [0, [Validators.required, NumberValidatorsService.max(100), NumberValidatorsService.min(0)]], }); 
  6. In the template, you can display the errors as follows:

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

1 Comment

They are better until you need to wire up disabled at which point you find out that it's a massive hassle to get that to work properly. You end up having to create all sorts of complex subscriptions, set accessors, and change detectors just to dynamically disable your forms. Awful that Angular decided to leave out the ability to provide a function to the disable initialization in reactive form controls.
4

I've found this as a solution. Create a custom validator as follow

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

and under constructor include the below code

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

where customForm is a FormGroup and _builder is a FormBuilder.

Comments

4

Angular has min and max validators but only for Reactive Forms. As it says in the docs: "The validator exists only as a function and not as a directive."

To be able to use these validators in template-driven forms you need to create custom directives. In my implementation i use @HostBinding to also apply the HTML min/max-attributes. My selectors are also quite specific to prevent validation running on custom form controls that implements ControlValueAccessor with a min or max input (e.g. MatDatePickerInput)

min-validator:

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

1 Comment

These are the most complete directives of the whole answer. It remains to check if the integrated Validators validates in all scenarios.
3

Angular 6 supports min & max validators: https://angular.io/api/forms/Validators

You can use those for static & dynamic values.

Static:

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

Dynamic:

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

3 Comments

@sumitkanoje In Angular 5 the following worked for me in a template driven form: this.templateItem1 = new FormControl('', [ Validators.required, Validators.pattern('[0-9]+'), Validators.min(1), Validators.max(10) ]); For an input field that was required, allows numbers only, and must be in the range of [1-10]. In the HTML, the element is: <input type="text" class="form-control" id="item1" formControlName="templateItem1"> (and exists within a form-group & form element), and then you can use the form-control-feedback with templateItem1.errors .dirty .touched for validation messages.
it isn't template driven form
From Angular documentation about min and max: "The validator exists only as a function and not as a directive." Min max only work with reactive forms.
3

Angualr itself provide a min and max number validation functionality.

Example - we have a field like age range then see the use of validation.

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

the age always be between 1 to 18.

Comments

2

In my template driven form (Angular 6) I have the following workaround:

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

Alot of the above examples make use of directives and custom classes which do scale better in more complex forms, but if your looking for a simple numeric min, utilize pattern as a directive and impose a regex restriction on positive numbers only.

Comments

1

In latest Angular versions, min and max are already added. Here is the link: https://angular.io/api/forms/Validators#max

This is how I used Max validator in my project:

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

Initialize the form control and add the validator in the component:

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

You can also set validator dynamically on an event like this:

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

Hope it helps.

Comments

1

Find the custom validator for min number validation. The selector name of our directive is 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; } } 

Find the custom validator for max number validation. The selector name of our directive is 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; } } 

We can use customMax with formControlName, formControl and ngModel attributes.

Using Custom Min and Max Validator in Template-driven Form

We will use our custom min and max validator in template-driven form. For min number validation we have customMin attribute and for max number validation we have customMax attribute. Now find the code snippet for validation.

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

We can show validation error messages as following.

<div *ngIf="numberOne.errors?.customMin"> Minimum required number is 15. </div> <div *ngIf="numberTwo.errors?.customMax"> Maximum number can be 50. </div> 

To assign min and max number we can also use property biding. Suppose we have following component properties.

minNum = 15; maxNum = 50; 

Now use property binding for customMin and customMax as following.

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

2 Comments

This work for me, but you should edit the directive to cast to number because is comparing with string in "v > this.customMax" to "v > +this.customMax" because doen't work in angular 7
This can be because the input type might be equal to text instead of number. So you can either cast to a number or change the type to number
1

My version for strict compilers

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

Comments

0

USE

Validators.min(5) 

It can be used while creating a formGroup variable along with other validators, as in

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

Not sure if it is in Angular 2, but is available in Angular 5

Comments

0

I've added a max validation to amd's great answer.

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

Comments

0

This question has already been answered. I'd like to extend the answer from @amd. Sometimes you might need a default value.

For example, to validate against a specific value, I'd like to provide it as follows-

<input integerMinValue="20" > 

But the minimum value of a 32 bit signed integer is -2147483648. To validate against this value, I don't like to provide it. I'd like to write as follows-

<input integerMinValue > 

To achieve this you can write your directive as follows

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

Comments

-3

In your code you are using min and not minlength. Please also notice that this will not validate if a number is > 0 but its length.

1 Comment

The question was about how minlength is supported by NG2 validation while min is not, and if this is an intentional, out of the box thing - or just some piece of NG knowledge I'm missing. I know the difference between min and minlength :P

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.