Jeremy Likness
Jeremy Likness

Reputation: 7531

How do I create a custom validation directive (i.e. attribute for validation) in Angular 2.0?

I am working on a small project for Angular 2.0 using TypeScript. Right now to my understanding, Angular 2.0 does not have built-in validators for "min" and "max" tags. I understand how you can build a custom validator and attach it using FormBuilder but I wish to see how to create a custom validator directive that I can attach on an attribute. The HTML looks like this:

 <div class="unit">
<div class="label">Age (13 - 120):</div>
<div class="labelTarget">
    <input id="ageFrm" min="13" max="120" type="number" required=""
    ng-control="age" #age="form" [class.error]="!age.valid"
    [(ng-model)]="ageValue"/> {{age.valid}}
</div>
</div>

Right now age.valid is always true because there are no validators for min and max. I tried creating my own. First the custom validation functions:

import {Control} from "angular2/angular2";

export class HealthAppCustomValidators {

static min(min: number): Function {
  return (control: Control): {[key: string]: any} => {
    var v: number = Number(control.value);
    console.log("validating " + v + " against " + min);
    return v < min ?
              {"min": {"requiredMin": min, "actualMin": v}} :
              null;
  };
  }

static max(max: number): Function {
  return (control: Control): {[key: string]: any} => {
var v: number = Number(control.value);
    return v > max ?
              {"max": {"requiredMax": max, "actualMax": v}} :
              null;
  };
   }
}

And next the directives (this is based on examining the source code):

import {Attribute, Control, Directive, forwardRef, Provider, NG_VALIDATORS}   from "angular2/angular2";
import {HealthAppCustomValidators} from "./customValidators";

const MIN_VALIDATOR = new Provider(NG_VALIDATORS, {useExisting: 
forwardRef(() => MinValidator), multi:true});

@Directive({
  selector: '[min][ng-control],[min][ng-form-control],[min][ng-model]',
  providers: [MIN_VALIDATOR]
})
export class MinValidator {

  private _validator: Function;

  constructor(@Attribute("min") min: string) {
    console.log(min);
    this._validator = HealthAppCustomValidators.min(Number(min));
  }
  validate(c: Control): {[key: string]: any} { 
    console.log("validate");
    return this._validator(c); 
 }
}

However, whenever I actually import the directives the page load fails with the following error:

TypeError: validator is not a function
at     http://127.0.0.1:8080/node_modules/angular2/bundles/angular2.dev.js:12990:24
at Array.reduce (native)
at Function.ListWrapper.reduce (http://127.0.0.1:8080/node_modules/angular2/bundles/angular2.dev.js:4206:19)
at http://127.0.0.1:8080/node_modules/angular2/bundles/angular2.dev.js:12989:44
at http://127.0.0.1:8080/node_modules/angular2/bundles/angular2.dev.js:12990:24
at Array.reduce (native)
at Function.ListWrapper.reduce (http://127.0.0.1:8080/node_modules/angular2/bundles/angular2.dev.js:4206:19)
at Control.validator (http://127.0.0.1:8080/node_modules/angular2/bundles/angular2.dev.js:12989:44)
at Control.AbstractControl.updateValidity (http://127.0.0.1:8080/node_modules/angular2/bundles/angular2.dev.js:18871:27)
at  http://127.0.0.1:8080/node_modules/angular2/bundles/angular2.dev.js:14097:14

Any help with the correct way to do this without FormBuilder is greatly appreciated:

Upvotes: 3

Views: 976

Answers (1)

Eric Martinez
Eric Martinez

Reputation: 31787

As suggested by Jeremy,

the problem is solved since alpha 45 where they added support for Validator. The error message may be confusing though (you were providing a function, why didn't work?) but the commit message gives a clue

Currently, the only way for a directive to export a validator is by providing a function. This makes it ackward to write validators that depend on directive inputs. In addition to supporting functions as validators, classes implementing the Validator interface are supported too.

I couldn't find examples for custom validators in alpha 44 or below, so I can't say how they worked at that moment. And it's most likely they updated all their examples and working validators to work with alpha 45+.

Anyway, this was solved by upgrading angular2, to the most recent version (alpha 48 is the latest one by the way, I said alpha 47 in the comment, my bad) although it was required at least alpha 45.

Upvotes: 2

Related Questions