Ошибка углового пользовательского асинхронного валидатора
Мой асинхронный валидатор не работает, когда я фактически выполняю асинхронный вызов (но работает, когда я его Observable.of(result)
, html
выглядит так:
<div class="form-group">
<label for="emailAddress" class="control-label">Email</label>
<input type="email"
id="emailAddress"
class="form-control"
[(ngModel)]="parent.EmailAddress"
name="emailAddress"
[ngModelOptions]="{updateOn: 'blur'}"
appDuplicateEmailValidator
#emailAddress = "ngModel">
</div>
Валидатор в вопросе appDuplicateEmailValidator
,
Код проверки выглядит следующим образом:
public validate(control: AbstractControl): Observable<ValidationErrors | null> {
// return observableOf({ 'isDuplicateEmail': true });
return this.checkForDupeUserAndGetValidationState(emailAddress);
}
private checkForDupeUserAndGetValidationState(emailAddress): Observable<ValidationErrors | null> {
const validationStateObs: Observable<ValidationErrors | null> = new Observable(observer => {
this.adminService.getUser(emailAddress).subscribe(
(res: any) => {
const validationState = !!res ? observableOf({ 'isDuplicateEmail': true }) : null;
console.log('Observer next, validation state: ', validationState); // Gets correct val state
observer.next(validationState);
console.log('Is it hitting this'); // Gets hit
}, (err) => {
observer.next(null);
});
});
Важным примечанием является то, что когда я раскомментирую // return observableOf({ 'isDuplicateEmail': true });
все работает как положено. Но, как вы видите код выше, он не работает, даже несмотря на то, что наблюдаемая возвращает правильное значение (в журнале используется отладчик). Под "не работает" я подразумеваю, что элемент управления формы никогда не переходит в состояние ошибки, как показано:
<pre>IS INVALID: {{emailAddress.invalid}}</pre>
<pre>ERRORS: {{emailAddress.errors | json}}</pre>
Почему и как мне это исправить?
3 ответа
У вас 3 вопроса. 1. вам нужно на самом деле вернуть наблюдаемую 2. вы отправляете наблюдаемое вместо значения через своего наблюдателя 3. наблюдаемое необходимо завершить.
Вы могли бы сделать это:
private checkForDupeUserAndGetValidationState(emailAddress): Observable<ValidationErrors | null> {
const validationStateObs: Observable<ValidationErrors | null> = new Observable(observer => {
this.adminService.getUser(emailAddress).subscribe(
(res: any) => {
const validationState = !!res ? { 'isDuplicateEmail': true } : null; // just send the value
observer.next(validationState);
observer.complete(); //complete here
}, (err) => {
observer.next(null);
observer.complete(); // and complete here
});
});
return validationStateObs; // return it here
}
но гораздо проще и понятнее было бы просто вернуть ответ от вашего сервиса и использовать операторов вместо того, чтобы создавать наблюдаемый и вкладывать в него подписку.
private checkForDupeUserAndGetValidationState(emailAddress): Observable<ValidationErrors | null> {
return this.adminService.getUser(emailAddress).pipe(
map((res: any) => !!res ? { 'isDuplicateEmail': true } : null),
catchError((err) => observableOf(null))
)
}
Наблюдаемые http естественно завершаются после одного выпуска, так что вам не нужно беспокоиться о завершении или любой другой сложной логике, которая у вас была.
Вопрос в том, почему вы подписываетесь, а затем возвращаете это как новое Observable
? Я думаю, что вы должны быть в состоянии сделать это:
private checkForDupeUserAndGetValidationState(emailAddress): Observable<ValidationErrors | null> {
return this.adminService.getUser(emailAddress).pipe(map(
(res: any) => {
return !!res ? { 'isDuplicateEmail': true } : null;
}, catchError(err => {
return of(null);
})));
}
Таким образом, вы позволите самому асинхронному валидатору обрабатывать подписку для вас...
Надеюсь это поможет...
observableOf({ 'isDuplicateEmail': true })
возвращает наблюдаемое право? Вы должны поместить обычный метод в Observer.next(), а не наблюдаемый.
попробуйте удалить observableOf и протестируйте его. это должно быть что-то вроде этого:
private checkForDupeUserAndGetValidationState(emailAddress): Observable<ValidationErrors | null> {
const validationStateObs: Observable<ValidationErrors | null> = new Observable(observer => {
this.adminService.getUser(emailAddress).subscribe(
(res: any) => {
const validationState = !!res ? { 'isDuplicateEmail': true } : null;
console.log('Observer next, validation state: ', validationState); // Gets correct val state
observer.next(validationState);
console.log('Is it hitting this'); // Gets hit
}, (err) => {
observer.next(null);
});
});
Я надеюсь, что это работает так