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.