简体   繁体   中英

Angular2 async validator for username input field

I'm trying to validate if a username is taken and assign the result to a boolean:

    isUsernameAvailable(control: FormControl) {
   this.authenticationService.isUsernameAvailable(control.value)
       .subscribe(
           result => console.log(result.taken),
           error => console.log(error)
       );
}

This takes an input string and returns a boolean value whether it matches a user in the database or not. It works as expected when called with a string, but I want to call it with the field's input as parameter like this:

         this.username = new FormControl(null, 
         Validators.compose([
             Validators.required,
             Validators.minLength(3),
     ]),this.isUsernameAvailable(this.username.value)); // <-- this is wrong obviously

I found out that this works when I add it to ngOnInit() :

     this.username.valueChanges.debounceTime(400).subscribe(value => {return this.isUsernameAvailable(value) });

So my question is how to make it so my validator takes the input text from the input field and checks if the username is taken. EDIT: When I use only this.isUsernameAvailable I get

"Cannot read property 'authenticationService' of undefined" error

. I also tried to bind this: this.isUsernameAvailable.bind(this), but then I get

Cannot read property 'subscribe' of undefined error

I also updated my code to what I last tempered with. (the console log reports the correct value, but the validator returns errors).

So apparantely I just don't know what I'm doing, but I got it working somehow. I'm pasting my solution if someone ever is stuck on the same problem. My final code is:

this.username = new FormControl(null, [
            Validators.required,
            Validators.pattern(this.usernamePattern),
            Validators.minLength(3),
            Validators.maxLength(15)
        ], this.validateUsername.bind(this)
    );


  validateUsername(c: FormControl) {
    return this.usernameAvailable(c.value);
}

  private validationTimeout: any;

  usernameAvailable(username: string) {
    clearTimeout(this.validationTimeout);
    return new Promise((resolve) => {
        this.validationTimeout = setTimeout(() => {
            let req = this.authenticationService.isUsernameAvailable(username);
            req.subscribe(result => {
                    if (result.taken) {
                        resolve({taken: true})
                    }
                    else {
                        resolve(null)
                    }
                },
                error => this.logger.error(error.message))
        }, 600);
    });
}

Keep in mind that you can't use debounceTime directly on the async validator, as it will always initiate immediately after each keystroke, so you have to timeout your request somehow. There's probably a better way to do it, this is what worked for me.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM