2
votes

Here is the registration form, created with standard angular 2 form builder:

this.form = this.formBuilder.group({
    login : [
        this.formValue.login,
        [
            Validators.required,
            Validators.minLength(loginLength.min),
            Validators.maxLength(loginLength.max),
            regexpValidator(loginPattern),
        ],
        //my custom validator class to check if login already exists
        LoginExistenceValidator,
    ],
    password : [
        this.formValue.password,
        [
            Validators.required,
            Validators.minLength(passwordLength.min),
            Validators.maxLength(passwordLength.max),
        ],
    ],
});

As mentioned here - http://blog.thoughtram.io/angular/2016/03/14/custom-validators-in-angular-2.html#custom-validators-with-dependencies :

It turns out that a validator can also be a class as long as it implements a validate(c: FormControl) method.

Hence it is possible to inject service to acess remote data from validator.

So I created such validator:

import { Injectable, Inject, forwardRef } from '@angular/core';
import { Validator, FormControl }         from '@angular/forms';

import { UsersAdapter } from 'common/adapters/users';

@Injectable()
export class LoginExistenceValidator implements Validator {

    private adapter;

    constructor(@Inject(forwardRef(()=>UsersAdapter)) adapter) {
        debugger
    }

    validate(control: FormControl) {
        console.log("yep i'm called");
        return function(control: FormControl){

            //validation logic

            let validator = new Promise((resolve)=>{
                //mock random success/fail for a while
                setTimeout(()=>{
                    let random = Math.round(Math.random());
                    let value = random ? null : { reserved: true };
                    console.log(resolve);
                    resolve(value);
                },2000);

            });

            return validator;

        }
    }
}

UserAdapter is a wrapper around Angular Http, which retrieves data. Now I'm not using it and every validation call should return random success/fail result.

This code throws such error in browser:

EXCEPTION: Cannot read property 'subscribe' of undefined

Error occured because Angular do not actually calls validate(), and FormControl instance passed to constructor instead of provided UserAdapter service.

When I try to use function instead of class, everything works fine. How can I tell angular to use my validation class properly? Thanks in advance.

1

1 Answers

1
votes

The sentence you quoted was about a validator directive that is applied using a selector on the element.

If you to use it in reactive forms you need to pass a function

The validate() method should return a Promise or Observable not a function that returns an Promise or Observable.

validate(control: FormControl) {
    console.log("yep i'm called");
        return = new Promise((resolve)=>{
            //mock random success/fail for a while
            setTimeout(()=>{
                let random = Math.round(Math.random());
                let value = random ? null : { reserved: true };
                console.log(resolve);
                resolve(value);
            },2000);

        });
    }
}

then use it like

this.form = this.formBuilder.group({
    login : [
        this.formValue.login,
        [
            Validators.required,
            Validators.minLength(loginLength.min),
            Validators.maxLength(loginLength.max),
            regexpValidator(loginPattern),
        ],
        //my custom validator class to check if login already exists
        new LoginExistenceValidator().validate,
    ],
    password : [
        this.formValue.password,
        [
            Validators.required,
            Validators.minLength(passwordLength.min),
            Validators.maxLength(passwordLength.max),
        ],
    ],
});