I've written a custom validator for Angular2 Forms. It simply compares the input to a blacklist, this works fine so far. With one exception: if the blacklist is updated after form validation is done, the form won't be validated again until the input-field changes. To fix this I'm getting the template variable in my component and trigger an update manually.
@ViewChild('email') emailNgModel: NgModel;
...
this.emailBlacklist = this.emailBlacklist.concat(email);
let sub = this.zone.onStable.asObservable().subscribe(() => {
if (sub) sub.unsubscribe();
this.zone.run(() => {
this.emailNgModel.control.updateValueAndValidity();
});
});
I'd much prefer to listen to changes in my directive and trigger the update from there (see TODO below)
export const BLACKLIST_VALIDATOR: any = {
provide: NG_VALIDATORS,
useExisting: forwardRef(() => BlacklistValidatorDirective),
multi: true
};
@Directive({
selector: '[validateBlacklist][formControlName],[validateBlacklist][formControl],[validateBlacklist][ngModel]',
providers: [BLACKLIST_VALIDATOR]
})
export class BlacklistValidatorDirective implements Validator, OnChanges {
@Input('validateBlacklist') blacklist;
constructor() {
}
ngOnChanges(changes: SimpleChanges): void {
if ('blacklist' in changes) {
// TODO trigger ngModel.control.updateValueAndValidity()
}
}
validate(c: AbstractControl): {[p: string]: any} {
return validateBlacklist(this.blacklist, c.value);
}
}
export function validateBlacklist(blacklist: string[], value) {
if (blacklist && blacklist.indexOf(value) >= 0) {
return {
blacklist: true
};
}
return null;
}
Now the question is, how can I get ngModel from the host? Or how do I get other directives on the same host in general ?
Just inject it
constructor(private ngModel:NgModel) {
I'm pretty sure this will do exactly what you want.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With