#angular #validation #angular7
#angular #проверка #angular7
Вопрос:
Я создаю приложение Angular NodeJS SQLite. В одном из моих представлений мне нужно ввести IP-адрес в реактивной форме. Этот IP-адрес должен быть уникальным в базе данных, поэтому я использую асинхронный валидатор для проверки каждого ввода символа, если это значение находится в БД.
Следуя документации angular и некоторым видеороликам, мне удалось собрать этот код:
Определение элемента управления формой:
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 amp;amp; 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-ответ, состоящий из IP-адресов, которые соответствуют управляющему значению. Метод отлично работает с использованием .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(
он не достигает метода API rest, который извлекает IP-адреса из базы данных. Я пытался использовать систему подписки, и она действительно извлекает IP-адреса, но я не думаю, что именно так она должна возвращать 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);
});
}
}
}
Из теории я знаю, что асинхронные валидаторы запускаются только тогда, когда валидаторы синхронизации возвращают значение null, но я действительно не знаю, что это означает в данном случае, может ли это быть проблемой?
Это только для образовательных приложений, поскольку я пытаюсь понять асинхронные валидаторы, чтобы я мог использовать их в будущем. Приветствуются любые предложения о проблеме или самом сообщении.
Ответ №1:
Если вы посмотрите на подпись для FormControl
в документах, вы увидите, что параметры конструктора являются:
formState: any = null,
validatorOrOpts?: ValidatorFn | AbstractControlOptions | ValidatorFn[],
asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[]
Я разделил параметры на их отдельные строки, чтобы подчеркнуть, что их три.
Я полагаю, что ваша проблема может заключаться в том, что вы смешиваете свой uniqueIPValidator AsyncValidatorFn
с синхронным Validators.required ValidatorFn
.
Попробуйте изменить:
ip: [this.nodo.ip,[Validators.required, uniqueIPValidator(this._nodeService)]],
Для
ip: [this.nodo.ip, Validators.required, uniqueIPValidator(this._nodeService)],
Делая это, вы будете предоставлять uniqueIPValidator(this._nodeService)
параметр в качестве третьего параметра (для асинхронных валидаторов) вместо того, чтобы внутри массива второго параметра.
Комментарии:
1. Именно то, что мне было нужно, спасибо! Думаю, мне нужно еще раз прочитать документы формы.
2. Добро пожаловать! Я рад, что это решило вашу проблему. Честно говоря, это была очень простая ошибка 🙂