1
votes

As I understand it (perhaps not well as I only started looking at this today) there is are validators built in to Angular that will check the max and min value of an <input type='number'>.
I tried to get this working in the app I'm building but it only comes up invalid when the input is completely empty. Other values validate, even numbers outside of my min/max range.

I tried to replicate it in a plunk but here it is just always valid. I'm at the end of a long day - can anyone just explain what I have to do to make the field in my plunk be valid with values of 5-10 and invalid when outside this range, empty or otherwise just...invalid.

4
You're never using the validators anywhere. They will only be applied by default on template-driven forms in angular 5. - JB Nizet
Looks like the min/max support was removed because adding it was a breaking change. See this: github.com/angular/angular/issues/17491 and this: github.com/angular/angular/issues/18830 - DeborahK

4 Answers

4
votes

I strongly recommend you use Reactive Forms instead.
With Reactive Forms your business logic stays in the component.ts code, keeping your templates more clear and easier to reason about.

WorkingExample (based on your original plunk)


Explanation:

component.ts

myForm = new FormGroup({}) // Instantiating our form

constructor(private fb: FormBuilder){ // Injecting the ReactiveForms FormBuilder.
  this.myForm = fb.group({
    // Adding the "myNum" input to our FormGroup along with its min-max Validators.
    'myNum': ['', [Validators.min(5), Validators.max(10)]] 
  })
}

component.html - template

<form [formGroup]="myForm"> <!-- Binding myForm to the form in the template -->

  <label for="myNum">Some Val</label>
  <!-- formControlName binds our myNum field declared in the ts code. -->
  <input type='number' id="myNum" formControlName="myNum">

</form>
3
votes

As the documentation linked in your question states :

max() exists only as a function, not as a directive

That's due to the two issues cited in @DeborahK comments. But still if you really want to use template-driven forms you can put those directives back in the place :

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

@Directive({
  selector: 'input[max]',
  providers: [{provide: NG_VALIDATORS, useExisting: MaxValidator, multi: true}]
})
export class MaxValidator implements Validator {
  @Input() max:number;
  validate(control: AbstractControl): {[key: string]: any} {
    if(typeof this.max == 'string') this.max = +this.max;
    return this.max ? Validators.max(this.max)(control) : null;
  }
}

I'll let you refactor it to get the MinValidatorone !

0
votes

I have a custom number range validator here: https://github.com/DeborahK/MovieHunter/tree/master/src/app/shared

It basically looks like this:

static range(min: number, max: number): ValidatorFn {
    return (c: AbstractControl): { [key: string]: boolean } | null => {
        if (c.value && (isNaN(c.value) || c.value < min || c.value > max)) {
            return { 'range': true };
        }
        return null;
    };
}
0
votes

As @Mihailo's answer is correct, but in my case I was using

 'myNum': ['', [Validators.minLength(5), Validators.maxLength(10)]] 

instead of

 'myNum': ['', [Validators.min(5), Validators.max(10)]] 

notice min is different from minLength and max is different from maxLength.