26

1. Is it even supported by Angular yet ? see this open issue

2. If it is, then what is wrong in the code below

export class someClass{

    myForm:ControlGroup;

    constructor(public http:Http, public formBuilder:FormBuilder)
       this.myForm = formBuilder.group({
            ImageId: ["", Validators.required, this.asynValidator]
    });

    asyncValidator(control: Control): {[key: string]: any} {

        return new Promise (resolve => {

          let headers = new Headers();
          headers.append('Content-Type', 'application/json');

          this.http.get('http://localhost/ImageIdValidate?id='+ control.value, {headers:headers})
                .map(res => res.json())
                .subscribe(data => {
                    console.log(data);
                    if(data != null) {
                        resolve({"duplicate": true})
                    }
                    else resolve(null);      
                })
            });
        });
      }
    }

It doesn't even make a server request.

3 Answers 3

28

You need to bind your method on the component instance itself as described below:

this.myForm = formBuilder.group({
            ImageId: ["",    
               Validators.required, 
               this.asynValidator.bind(this)]
    });

Otherwise you won't be able to use the http property to execute your request.

This article could also give you some hints about asynchronous form validation (see the section "asynchronous validation"):

Sign up to request clarification or add additional context in comments.

4 Comments

In fact, it's the way JavaScript works. When you reference a method you lose the object it's attached on. You can force this using the bind method...
When I start to think that I'm on my way to be a PRO someday, things like this make me laugh. But anyway, is this question related ?
In fact OOP in JavaScript is different front the ones of languages like Java and C++. With the class keyword, you don't really define "true" classes like with languages. JavaScript usés prototype-based OOP. Yes the question you quoted is related to this problem.
And @ThierryTemplier's other answer showing an alternative to .bind() using a closure.
3

as of newer versions of Angular, but pre version 5.0.0 you would add the async validator as the third argument for your formcontrol:

myControl: ['', [Validators.required], [this.asyncValidator.bind(this)]]

since version 5.0.0 you can now mark the validators like so:

myControl: ['', {validators: [Validators.required], 
                 asyncValidators:[this.asyncValidator.bind(this)]}]

1 Comment

I just implemented an async validation function, and I also had to add NG_ASYNC_VALIDATORS provider to the component! (Which is an annoying bit of magic!!)
0

Hello guys thanks for the solution. However it didnt work for me outta the box.

the problem was the async validator had to be a next parameter as part of the validators. so what worked for me was

this.myForm = formBuilder.group({
        ImageId: ["",    
           [Validators.required], 
           [this.asynValidator.bind(this)]]
});

and tadaa!! the headache was gone. hope it helps someone.

2 Comments

The only difference i can see is you added some extra [] comparing to the answer post. And you have not mentioned why is the extra [] require. This is not a helpful anser
The extra [] brackets are required because async validators now have to be listed as the third parameter. Sync validators are listed in the second parameter, async validators in the third.

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.