2

当我实际进行异步调用时,我的异步验证器不工作(但当我用 . 模拟它时工作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 });,一切都按预期工作。但是您看到上面的代码的方式,它不起作用,即使 observable 返回正确的值(将其记录为使用过的调试器)。“它不起作用”是指表单控件永远不会进入错误状态,如下所示:

<pre>IS INVALID: {{emailAddress.invalid}}</pre>
<pre>ERRORS: {{emailAddress.errors | json}}</pre>

为什么以及如何解决它?

4

3 回答 3

3

你有3个问题。1. 您需要实际返回您的 observable 2. 您正在通过观察者发送一个 observable 而不是一个值 3. observable 需要完成。

你可以这样做:

  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 observables 在一次发射后自然完成,因此您无需担心完成或您拥有的任何其他复杂逻辑。

于 2019-08-20T15:58:19.817 回答
1

问题是,您为什么订阅然后将其作为新的返回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);
      })));
  }

这样,您将让异步验证器本身为您处理订阅...

希望这可以帮助...

于 2019-08-20T15:43:10.123 回答
0

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);
        });
    });

我希望它以这种方式工作

于 2019-08-20T15:18:35.610 回答