我可以使用 Subject 来制作自定义异步验证器吗?

Can i use a Subject to make a custom async validator?

我是否有机会通过一个主题实现这一目标?目前我只是通过承诺实现了这一点。所以我调用了 resolve 方法,它工作正常。

我正在尝试执行以下操作。

forbiddenEmail(control: FormControl): Observable<any> {

    const obs = new Subject();
    setTimeout(() => {
      if (control.value === 'test@test.com') {
        obs.next({'emailIsForbidden': true});
      } else {
        obs.next(null);
      }
    }, 2000);
    return obs;
  }

在这里,我试图在值为 test@test.com 时发出事件,否则为 null,正如 Angular 中的文档所说的验证器。 我试图模拟让我们说一个后端服务,这就是为什么我实现 setTimeout 功能并给出 2 秒的超时。 现在的问题是,当我检查放置验证器的输入元素(电子邮件输入元素)时,总是显示 class ng-pending 。 所以,出于某种原因我没有订阅它我知道。但我怎么能?

这是我在 FormGroup 中调用验证器的地方。

ngOnInit() {
    this.signupForm = new FormGroup({
      'userData': new FormGroup({
        'username': new FormControl(null, [Validators.required, this.forbiddenNames.bind(this)]),
        'email': new FormControl(null, [Validators.required, Validators.email], this.forbiddenEmail.bind(this))
      }),
      'gender': new FormControl('male'),
      'hobbies': new FormArray([])
    });
  }

根据文档,您可以通过返回可观察对象来实现: https://angular.io/api/forms/AsyncValidatorFn

我试图用代码示例来证明它,但它看起来并没有像它应该的那样工作...

看起来像 angular 问题本身,这里报告:https://github.com/angular/angular/issues/13200

您需要完成您的 observable:

setTimeout(() => {
  if (control.value === 'test@test.com') {
    obs.next({'emailIsForbidden': true});
  } else {
    obs.next(null);
  }
  obs.complete();
}, 2000);

但这可以用更简单的方式定义:

forbiddenEmail2(control: FormControl): Observable<any> {
  const result = control.value === 'test@test.com' ? {'emailIsForbidden': true} : null;
  return Observable.of(result).delay(2000);
}

这也更正确,因为它实际上是在调用验证程序时验证输入,而不是在 2 秒后验证输入。在更现实的用例中:您将立即获得输入,并将其发送到后端。

演示:http://plnkr.co/edit/qAdl7lTaKzn0bUNOp8fy?p=preview

当然,只是 return 带有 asObservable() 的主题:

forbiddenEmail(control: FormControl): Observable<any> {
  const subject = new Subject();

  setTimeout(() => {
    if (control.value === 'test@test.com') {
      subject.next({ emailIsForbidden: true });
    } else {
      subject.next(null);
    }
  }, 2000);

  return subject.asObservable();
}