7

I was trying to find the information, if there are any built-in validators, that check if the input is a positive number?

I was trying to build the following:

static nonZero(control:Control) {
    if (Number(control.value) < 0) {
        control.setErrors({nonZero: true})
    } else {
    control.setErrors(null)
    }
}

However, I didn't know how to use it in my form builder:

this.form = _formBuilder.group({
            field:['', Validators.required]})

What am I doing wrong?

uksz
  • 18,239
  • 30
  • 94
  • 161

8 Answers8

8

You can configure it this way by leveraging the Validators.compose method:

this.form = _formBuilder.group({
        field:['', Validators.compose([
                     Validators.required, nonZero ])
        ]});

This allows you to define your two synchronous validators for the field.

Edit

I would implement the validator this way:

static nonZero(control:Control):{ [key: string]: any; } {
  if (Number(control.value) < 0) {
    return {nonZero: true};
  } else {
    return null;
  }
}
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • Actually, this throws me the following error: Argument of type '((control: Control) => void)[]' is not assignable to parameter of type 'ValidatorFn[]'. Type '(control: Control) => void' is not assignable to type 'ValidatorFn'. Type 'void' is not assignable to type '{ [key: string]: any; }'. – uksz Jun 29 '16 at 11:59
  • In fact, I would implement the validator a bit differently. I updated my answer... – Thierry Templier Jun 29 '16 at 12:02
6

You can also use the built-in validator min with Number.MIN_VALUE to accept every positive value.

For example:

this.form = _formBuilder.group({
    field:['', [Validators.required, Validators.min(Number.MIN_VALUE)]]
});
Fabrizio Rizzi
  • 298
  • 3
  • 6
5

Little refactored:

 export function positiveNumberValidator(): ValidatorFn {
      return (control: AbstractControl): { [key: string]: any } => {
        const isNotOk = Number(control.value) < 0;
        return isNotOk ? { nonPositive: { value: control.value } } : null;
      };
 }

and if you want to use it in template as Directive:

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

@Directive({
  selector: '[prePositiveNumber]',
  providers: [{ provide: NG_VALIDATORS, useExisting: PositiveNumberDirective, multi: true }]

})
export class PositiveNumberDirective implements Validator {

  validate(c: AbstractControl): { [key: string]: any; } {
    return positiveNumberValidator()(c);
  }
}

export function positiveNumberValidator(): ValidatorFn {
  return (control: AbstractControl): { [key: string]: any } => {
    const isNotOk = Number(control.value) < 0;
    return isNotOk ? { nonPositive: { value: control.value } } : null;
  };
}

Template:

 <input type="number"
        class="full"
        name="shipmentVolume"
        required
        prePositiveNumber
        [(ngModel)]="someModel" />

When using as Reactive forms you can compose validators, but also it can be used without compose:

this.form = _formBuilder.group({
        field:['', Validators.required, positiveNumberValidator()] });
Yerkon
  • 4,548
  • 1
  • 18
  • 30
3

You can combine min Validator and a regex pattern Validator:

 field: ['', [Validators.required, Validators.min(1), Validators.pattern('^(0|[1-9][0-9]*)$')]],
user1233043
  • 126
  • 7
3

You could do something like,

.js

  orderFormGroup = new FormGroup({
    weight: new FormControl('', [Validators.required, Validators.min(0)])
  });

This would allow less than and equal to zero values, if you want values more than zero then you could mention Validators.min(0.1)

.html

  <input type="number" step="0.1" name="orderWeight" formControlName="weight" max="35" min="0" class="clr-input form-control">

Note that the min="0" would only ensure that the front-end increase or decrease wouldnt go passed 0. The actual input validation is handled in .js

Niveditha Karmegam
  • 742
  • 11
  • 28
0

I'd use same compose methodology, but implement a min function, that you can pass 1 too.

import { ValidatorFn, AbstractControl } from '@angular/forms';
export function min(min: Number): ValidatorFn {
    return (control: AbstractControl): {[key: string]: any} => {
      const input = control.value,
            isValid = input < min;
      if(isValid) 
          return { 'minValue': {min} }
      else 
          return null;
    };
}


this.pnFG = this.fb.group({
  pageNumberInput: [this.pageNumber, 
                    Validators.compose([
                        Validators.required,
                        min(1)
                    ])
                  ]
});
JGFMK
  • 8,425
  • 4
  • 58
  • 92
0

the solution that requires no additional code

[Validators.required, Validators.min(1 / Number.MAX_VALUE)]

the solution with validator that return error object that is equivalent to Validators.min, so the error message is handled appropriately

export function positiveNumberValidator(control: AbstractControl): { min: { min: number, actual: string | number } } {
  const value = parseFloat(control.value);
  const isValid = !isNaN(value) && value > 0;
  if (isValid) {
    return null;
  }
  return { min: { min: 0, actual: value ?? '' } };
}
Oleg Polezky
  • 1,006
  • 14
  • 13
-1
<input type="number" ng-model="size" name="size" min="0" max="10" integer />

Easy as that!

Andris
  • 3,895
  • 2
  • 24
  • 27
  • Hey @user3564943 - Could you maybe add onto your answer to elaborate? Also, is this the integer directive you're using? https://www.npmjs.com/package/angular-integer – jarodsmk Jun 06 '18 at 12:09