angular - 使用响应式表单和等待服务方法的角度自定义异步验证
问题描述
我正在尝试将 Angular 中的 AsyncValidation 与具有异步/等待的服务方法一起使用,以测试用户名是否存在。我不知道如何转换服务中的返回签名(user.service.ts)
Promise<boolean>
e.g.
async isUserNameAvailable(userName: string): Promise<boolean> {
}
至
Promise<ValidationErrors | null> | Observable<ValidationErrors | null>
e.g.
validate(control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> {
}
在验证器/指令中。
user.service.ts:
async isUserNameAvailable(userName: string): Promise<boolean> {
var query = this.db.collection("users").where("name", "==", userName);
try {
const documentSnapshot = await query.get();
if (documentSnapshot.empty) {
return true;
} else {
return false;
}
} catch (error) {
console.log('Error getting documents', error);
}
}
现有用户名验证器.directive.ts
import { Directive } from '@angular/core';
import { UserService } from './user.service';
import { AbstractControl, ValidationErrors, NG_ASYNC_VALIDATORS, AsyncValidatorFn, AsyncValidator } from '@angular/forms';
import { Observable, timer } from 'rxjs';
import { map, filter, switchMap } from 'rxjs/operators';
export function existingUsernameValidator(userService: UserService): AsyncValidatorFn {
return (control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
let debounceTime = 500; //milliseconds
return Observable.timer(debounceTime).switchMap(()=> { //ERROR BECAUSE OF TIMER
return userService.isUserNameAvailable(control.value).map( //ERROR BECAUSE OF map
users => {
return (users && users.length > 0) ? {"usernameExists": true} : null;
}
);
});
};
}
@Directive({
selector: '[appExistingUsernameValidator]',
providers: [{provide: NG_ASYNC_VALIDATORS, useExisting: ExistingUsernameValidatorDirective, multi: true}]
})
export class ExistingUsernameValidatorDirective implements AsyncValidator {
constructor(private userService: UserService) { }
validate(control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> {
return existingUsernameValidator(this.userService)(control);
}
}
user.component.ts:
name: new FormControl('', {
validators: [Validators.required],
asyncValidators: [existingUsernameValidator(this.userService)]
}),
Stackblitz:https ://stackblitz.com/edit/angular-ivy-cd866c?file=src%2Fapp%2Fuser.service.ts
有谁知道如何使用 Reactive Forms 实现这一目标?
解决方案
刚刚existingUsernameValidator
在 Stackblitz 中纠正了
export function existingUsernameValidator(userService: UserService): AsyncValidatorFn {
return (control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
let debounceTime = 500; //milliseconds
const debounceTimer = timer(debounceTime)
return debounceTimer.pipe(switchMap(()=> {
return userService.isUserNameAvailable(control.value)
.then(result => {
return result ? {"usernameExists": true} : null;
});
}));
};
}
更新isUserNameAvailable
于UserService
async isUserNameAvailable(userName: string): Promise<boolean> {
const query = this.db.collection("users").where("name", "==", userName);
return query.get()
.then(function(documentSnapshot) {
return (documentSnapshot.empty as boolean)
})
.catch(function(error) {
console.log("Error getting documents: ", error);
return false;
});
}
试试看,如果现在一切就绪,请告诉我。还更新了 stackblitz
希望能帮助到你!
编辑:清理后的代码
代销功能
export function existingUsernameValidator(userService: UserService): AsyncValidatorFn {
return (control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
const debounceTime = 500; //milliseconds
return timer(debounceTime).pipe(switchMap(()=> {
return userService.isUserNameAvailable(control.value)
.then(result => result ? {"usernameExists": true} : null);
}));
};
}
用户服务
async isUserNameAvailable(userName: string): Promise<boolean> {
return this.db.collection("users").where("name", "==", userName).get()
.then(documentSnapshot => documentSnapshot.empty as boolean)
.catch(error => {
console.log("Error getting documents: ", error);
return false;
});
}
推荐阅读
- angular - 如何循环遍历 html 中的 Set
- scala - 如何在 Scala Dataframe 中显示分组数据
- python - os.path.abspath(__file__) 给出无效的位置并在文件路径中添加额外的 \'s
- sockets - Returned UDP packets lacking port and fail to arrive
- java - 我想打印除最后一个之外的所有字母,然后是最后两个,然后是最后 3 个
- webpack - Webpack 将 CLI 环境变量导出到窗口对象
- c# - C# 中 Java Objects.hash 和 Objects.hashCode 的等价物
- azure - 我应该如何使用 .net core c# 从死信中读取更多消息?
- c# - 在python中动态构建表达式
- sql - SQL 检查当前日期是否为星期一