Angular 2 个异步表单验证器

Angular 2 async form validator

其实我卡在了这个问题

我创建了一个自定义异步验证器来检查用户名是否被占用。这是我绑定它的地方:

 'name': ['',[Validators.required, Validators.minLength(4), Validators.minLength(4)], this.asyncName.bind(this)],

这是我的验证器:

asyncName(control: FormControl) {
    this.names$ = this.af.database.list('/usernames')
     .map (name => {
            name.filter(name => {
                if (name.name.toLowerCase() === control.value.toLowerCase()) {
                     console.log("Username taken");  
                     return {
                        valid: false
                    }; 
                } else {
                    console.log("Username available");
                    return {
                        valid: true
                    };
                }
            })
        });             

    return this.names$;
};

所以这个验证器有效。如果用户名被占用,它会记录 "Username taken" else "Username available".

我的问题: return 语句不起作用。当我订阅表单的状态时,它仍然是 "Pending" 而不是 "Valid" 或 "Invalid"。 Angular2 认为验证仍然是 运行.

有谁知道如何创建有效的 return 或基于 observables 的 resolve 语句?

也许我自己订阅并用 resolve() 函数做点什么。但是我所有的尝试都没有用。

提前致谢!!!

您可以尝试 .first() 以确保可观察对象在第一个事件后关闭:

asyncName(control: FormControl) {
    this.names$ = this.af.database.list('/usernames').first()
    .map(...

不确定这是否是实际问题。

我遇到了类似的问题。就我而言,我有类别列表,我想检查类别名称是否唯一。这是我的验证器:

export class CategoryFormComponent {
  constructor(
    private firebase: AngularFireDatabase
  ) {}
  
   categoryExists(control: AbstractControl) {
    return  this.firebase.database
        .ref(`categories/${this.uid}`) // user's uid
        .orderByChild('name')
        .equalTo(control.value)
        .once('value')
        .then((snapshot) => {
          return snapshot.val() ? { categoryExists: true } : null;
      });
  }
}

如您所见,您可以在数据库中进行搜索(性能更高),然后使用 一次 returns Promise。