validering - Angular 4 - Hur man anropar anpassad validator vid blur?


Jag har ett formulär som styrs av en mall där jag behöver göra ett HTTP-anrop för att kontrollera om en användares e-postadress är tillgänglig.

Jag behöver göra detta samtal när e-posttextfältet tappar fokus, jag försöker göra det via en anpassad validator-direktiv men tyvärr anropas valideringen vid varje tangenttryckning (det verkar vara standardbeteendet vilket jag inte vill i detta scenario).

@Directive({
selector: '[app-email-check][ngModel]',
providers: [
    {
        provide: NG_ASYNC_VALIDATORS,
        useExisting: forwardRef(() => EmailCheckValidator),
        multi: true
    }
]

})

export class EmailCheckValidator implements Validator, OnInit {
validator: ValidatorFn;

constructor(private _emailHelper: EmailHelperService) {

}

ngOnInit() {

}


validate(control: FormControl) {
    return this._emailHelper.isEmailAvailable(control.value)
        .then((response) => {
            if (response) {
                return null;
            } else {
                return { emailCheckValidator: { valid: false } };
            }
        });
}

}

Jag ser att i Angular 5 har de löst detta genom att låta dig specificera uppdateringstypen:

[ngModelOptions]="{ updateOn: 'blur' }"

Redigera - Lagt till HTML

<input type="text" name="emailAddress" id="emailAddr"
 [(ngModel)]="user.emailAddress" app-email-check  #emailAddress="ngModel" required />

Har någon stött på detta problem tidigare? All hjälp skulle uppskattas, tack!

Svar #1

Jag löste detta genom att skapa en abstrakt klass som inaktiverar asynkrona validatorer när kontrollen får fokus. När kontrollen förlorar fokus återaktiveras validatorerna och triggas.

export abstract class AbstractCustomValidator implements OnChanges {

    private asyncValidators: any;
    private wasChanged: any;


    @ContentChild(NgControl) formControl: NgControl;

    constructor() {
    }

    // On focus of control, clear all async validators so they do not fire on keypress
    @HostListener('focus', ['$event'])
    onFocus($event) {
        this.wasChanged = false;
        this.asyncValidators = this.formControl.control.asyncValidator;
        this.formControl.control.clearAsyncValidators();
    }

    @HostListener('window:keyup', ['$event'])
    onKeyup($event) {
        this.wasChanged = true;
    }

    ngOnChanges() {
        this.wasChanged = true;
    }

    // On blur of control, re-enable all async validators so they fire 
    @HostListener('blur', ['$event'])
    onBlur($event) {
        this.formControl.control.setAsyncValidators(this.asyncValidators);

        if (this.wasChanged) {
            this.formControl.control.updateValueAndValidity();
        }
    }
}