Search code examples
javascriptangularangular-forms

Angular 5 FormGroup validator web service result not triggering ngIF hasError


I have a custom FormGroup validator that does not correctly update the validator error state, after returning from a web service call that checks if a displayName is already in use.

In the code below, I know my html code is working because my component's validateDisplayName function displays "Display Name is already used" when the displayName input is empty. Then, as you start typing letters the web service is called to start validating the entry on the third letter - then the message disappears, When I type a displayName that matches one in the DB, the web service is correctly returning true, but a return { displayNameTaken: true }; call does not cause the error to display.

I know it has something to do with the Promise that the web service returns, but I cannot figure out a solution.

component.ts

ngOnInit() {
    this.dnFormGroup = this.formBuilder.group({
        displayName: ['', this.validateDisplayName.bind(this)]
    });    
}

public validateDisplayName(control: AbstractControl): any {
    console.log("RegisterComponent validateDisplayName - ENTRY");

    if(control.value.length >= 3) {

        return this.authService.validateDisplayName(control.value).then( 
            (res) => {
                console.log("RegisterComponent validateDisplayName - res: " +res);

                if(res) {
                    console.log("RegisterComponent validateDisplayName - displayName already used");
                    return { displayNameTaken: true };              
                } else {
                    console.log("RegisterComponent validateDisplayName - - displayName can be used");
                    return null;
                }
            },
            (err) => {
                console.log("RegisterComponent validateDisplayName - err: " +err);
                return { displayNameTaken: true };                            
            });
    }

    console.log("RegisterComponent validateDisplayName - ############## EXIT");
    return { displayNameTaken: true }; 
}

component-service.ts

public validateDisplayName(displayName: string) {
    console.log("AuthService validateDisplayName - displayName: " +displayName);  

    return this.http
        .get(environment.server_url +"profile_cont/displaynameexists/" +displayName +"/")
        .toPromise()
        .then(
            (response) => {
                const existsBool = response.json();
                console.log("AuthService validateDisplayName - existsBool: " +existsBool);            
                return existsBool;          
            },
            (error) => {
                console.log("AuthService validateDisplayName - error: " +error);  
                return true;          
    });
}

component.html

    <form [formGroup]="dnFormGroup">
    <fieldset>
        <div class="row">
            <section class="col col-6">
                <label class="input">
                <i class="icon-append fa fa-user"></i>
                <input formControlName="displayName" type="text" minlength="3" maxlength="10" placeholder="Display name">
                <b class="tooltip tooltip-top-right"> <i class="fa fa-user txt-color-teal"></i> Please provide a 3 to 10 char name for site display purposes.</b>
                </label>

                <div *ngIf="dnFormGroup.get('displayName').hasError && dnFormGroup.get('displayName').hasError('displayNameTaken')">
                    Display Name is already used
                </div>
            </section>
        </div>
    </fieldset>
</form>

Thanks, Bob


Solution

  • Ansync validator has to be a third argument, try:

    this.dnFormGroup = this.formBuilder.group({
        displayName: ['', null, this.validateDisplayName.bind(this)]
    });