Я создаю приложение Angular + NodeJS + SQlite. На одном из моих взглядов мне нужно ввести IP в реактивной форме. Этот IP-адрес должен быть уникальным в базе данных, поэтому я использую асинхронный валидатор, чтобы проверять каждый раз, когда символ вводится во входные данные, если это значение находится в БД.
Следуя угловой документации и некоторым видео, мне удалось собрать этот код:
Определение формы контроля:
createForm() {
this._addNodoForm = this._formBuilder.group({
name: [this.nodo.name,[Validators.required]],
ip: [this.nodo.ip,[Validators.required, uniqueIPValidator(this._nodeService)]],
status: [this.nodo.status, [Validators.required, Validators.maxLength(1)]],
vbus_ip: [this.nodo.vbus_ip, [Validators.required]],
physical_address: [this.nodo.physical_address, [Validators.required]],
tunnel_address: [this.nodo.tunnel_address, [Validators.required]],
transfer_rate: [this.nodo.transfer_rate, [Validators.required, Validators.max(9600), Validators.min(0)]],
});
}
Определение класса валидации:
export function uniqueIPValidator(nodeService: NodeService): AsyncValidatorFn {
return (c: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
if(c.value!=''){
return nodeService.getUniqueIp(c.value).pipe(map(
(addresses :any)=> {
return (addresses && addresses > 0) ? {"uniqueIP": true} : null;
}));
}
}
}
@Directive({
selector: '[uniqueIP]',
providers: [{ provide: NG_ASYNC_VALIDATORS, useExisting: UniqueIpValidatorDirective, multi: true }]
})
@Injectable()
export class UniqueIpValidatorDirective implements AsyncValidator{
constructor(private nodeService: NodeService) { }
validate(ctrl: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> {
return uniqueIPValidator(this.nodeService)(ctrl);
}
}
nodeService.getUniqueIp (): Этот метод возвращает http-ответ, состоящий из ips, которые соответствуют значению элемента управления. Метод отлично работает, используя .subscribe()
getUniqueIp(ip:string):Observable<any>{
return this._http.get(this.url + 'unique-ip/' + ip);
}
И, наконец, HTML-код ввода:
<input type="text" formControlName="ip" class="form-control" uniqueIP>
<div *ngIf="_addNodoForm.get('ip').errors?.uniqueIP">IP must be unique</div>
Проблема в том, что HTTP-вызов даже не выполняется с использованием .pipe(map(
, он не достигает метода rest API, который извлекает ips из БД. Я попытался использовать систему подписки, и она действительно получает ips, но я не думаю, что именно так он должен возвращать Observable<ValidationsErrors>
, так что в форме также не отображается ошибка.
export function uniqueIPValidator(nodeService: NodeService): AsyncValidatorFn {
return (c: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
if(c.value!=''){//to avoid making the http call when the input is empty
return nodeService.getUniqueIp(c.value).pipe().
subscribe(addresses => {
console.log('DIR: '+addresses);
if(addresses!=null){
return {"uniqueIP": true};
}
},error=>{
console.log(error);
});
}
}
}
Я знаю из теории, что валидаторы Async запускаются только тогда, когда валидаторы синхронизации возвращают ноль, но я действительно не знаю, что это значит в этом случае, может ли это быть проблемой?
Это только для образовательных систем, так как я пытаюсь понять асинхронные валидаторы, чтобы использовать их в будущем. Любые предложения по проблеме или сам пост приветствуются.