3

I'm trying to implement async custom validation and i have the validation class as below

export class CustomValidators{
_auth_service;
constructor(auth_service:AuthService){
    this._auth_service = auth_service;
}

usernameTaken(control: Control) {
    console.log(this._auth_service);
    let q = new Promise<ValidationResult>((resolve, reject) => {
    this._auth_service.emailtaken('email='+control.value).subscribe(data=>{
            var result = data.json().result;
            console.log(result);
            if(result===true){
                resolve({"usernameTaken": data});
            }else{
                resolve(null);
            }
        });
});
return q;
}

}

And in my component

this.customValidators = new CustomValidators(this._auth_service);

The i add it to form control like so

this.emailControl = new Control('',Validators.compose([Validators.required, Validators.pattern(ConfigService.EMAIL_REGEX)]),this.customValidators.usernameTaken); 

You can see that i am trying to inject a service in my validator. And then to use the validator function in my component i had to create an object of the validator and use it's method. I have debugged to see that the this._auth_service property appear undefined in my validator method. It seems to be populated fine in my validator constructor.

I do not want to use the validator as directive which i understand makes injecting service easy.

What could be the problem?

5
  • Does this._auth_service have a value in the constructor? Commented Apr 20, 2016 at 9:58
  • It does. But in the validator method it shows as undefined Commented Apr 20, 2016 at 9:59
  • It is undefined because this is not an instance of CustomValidators. Commented Apr 20, 2016 at 10:04
  • @dfsq So before using bind(), my validator was being called statically and was understandably out of context, and using bind makes the function being called as method of validator class? Commented Apr 20, 2016 at 10:08
  • Sort of. This is the same if you would do this: var user = {name: 'Thomas', getName: function() { return this.name }}; var getName = user.getName; getName(). Method is detauched from the base object, context lost. However, var getName = user.getName.bind(user) is bound to context and always execute properly. Commented Apr 20, 2016 at 10:12

1 Answer 1

7

Looks like you are losing a context. You should bind validator method to validator instance object explicitly:

this.emailControl = new Control('', Validators.compose([
  Validators.required, 
  Validators.pattern(ConfigService.EMAIL_REGEX)
 ]), this.customValidators.usernameTaken.bind(this.customValidators));
Sign up to request clarification or add additional context in comments.

6 Comments

Could you please elaborate what .bind() does in this case?
it should be noted (since the question is tagged TS)
Function.prototype.bind returns a new function that will invoke this.customValidators.usernameTaken with proper context. It is important because this.customValidators.usernameTaken is just a reference to a validator method which will have dynamic context, meaning that this inside of it depends on how this method is called, but this will not longer be this.customValidators.
Interesting. Thanks!
@drewmoore Bind is not harmful, it is very useful and powerful method for context execution control. Of course one should use it wisely, but the fact that it returns any is not always a problem (like in this case it's not at all). At the same time, using arrow function for what should be done with bind, looks hacky and weird. But it is possible of course too: () => this.customValidators.usernameTaken().
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.