Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom Validation in Angular2 forms

Tags:

angular

Following the example here :

https://angular.io/docs/ts/latest/guide/forms.html

My form looks like:

<input type="text" class="form-control" id="name"
               required
               [(ngModel)]="model.name" name="name"
               #name="ngModel" >
        <div [hidden]="name.valid || name.pristine" 
             class="alert alert-danger">

I want to add some custom validation to this form. I did find some advise about using ngFormModel and FormBuilders and Validation class, however I believe these are outdated and no longer recommended

( http://almerosteyn.com/2016/03/angular2-form-validation-component)

My question then is how do I add custom validation.

In angular 1.x I used to add functions to ngModel.$parsers and ngModel.$formatters pipeline. What is the equivalent in angular 2 ?

like image 611
runtimeZero Avatar asked Aug 27 '16 18:08

runtimeZero


1 Answers

I do it by using a model-driven approach, instead of template-driven. For example:

Form

<form [formGroup]="myForm">
    <label for="id-name">Name</label>
    <input type="text" id="id-name" formControlName="name">
    <label for="id-age">Age</label>
    <input type="text" id="id-age" formControlName="age">
</form>

Component

export class MyComponent implements OnInit {
    myForm:FormGroup;

    ngOnInit() {
        let fuv = FormUtils.validators;

        this.myForm = this.formBuilder.group({
            name: ['', Validators.required],
            age: ['', [Validators.required, fuv.isNumber]],
        });
    }
}

FormUtils

type ValidatorResult = {[key:string]:any};

function _isNumber(control:AbstractControl):ValidatorResult {
    let v = control.value;
    if (isPresent(v) && !isNumber(v) && !isEmptyString(v)) {
        return {'isNumber': false};
    }
    return null;
}

export class FormUtils {
      static validators = {
        isNumber: _isNumber
      }
}

Here, isPresent, isNumber, and isEmptyString are pretty straightforward:

isPresent(obj) --> return obj !== undefined && obj !== null;
isNumber(obj) --> return (typeof obj === 'number' && !isNaN(obj));
isEmptyString(obj) --> return obj === '';

Currently, Angular 2 gives you four useful validators: required, minLength, maxLength, and pattern. The last one is pretty powerful. You can write your own validators following a pattern similar to _isNumber above. If your validator requires a parameter (e.g. lessThan), then you can use a pattern similar to this:

function lessThan(maxVal:number):ValidatorFn {
    return (control:AbstractControl):ValidatorResult => {
        let value = control.value;

        if (isPresent(value) && !isEmptyString(value) && isNumber(value) && parseInt(value) >= maxValue) {
            return {'lessThan': {'maxValue': maxValue, 'actual': value}};
        }

        return null;
    };
}

I understand that this approach (model-driven) is different from the form that you posted in your question (template-driven). I hope it helps anyway.

like image 84
Carlos Mermingas Avatar answered Sep 22 '22 16:09

Carlos Mermingas