【问题标题】:Angular async validator is not called with switchMap不使用 switchMap 调用 Angular 异步验证器
【发布时间】:2021-01-26 03:40:09
【问题描述】:

我需要检查用户输入的用户名是否唯一。因此,我为来自目标元素的每个input 事件发送一个HTTP 请求。而且,当然,我需要对这个操作进行去抖动,以便在特定时间间隔内获得 1 个针对 X input 事件的 HTTP 请求。
问题是 - 一旦我添加switchMap,代码就会停止工作,并且永远不会调用switchMap 回调。
没有switchMap的工作代码:

public static createUniqueFieldValidator(
  target: 'username' | 'email' | 'phone',
  checker: (value: string) => boolean,
  userService: UserService
): AsyncValidatorFn {
  return (control: AbstractControl): Observable<NullableType<ValidationErrors>> => {
    if (!!control.value && checker(control.value)) {
      return fromPromise<SomeReturnedType>(
        userService.checkUnique({ [ target ]: control.value })
      ).pipe<NullableType<ValidationErrors>>(.......);
    }

    return of<null>(null);
  };
}

如果我添加 switchMap 它的回调永远不会被调用

public static createUniqueFieldValidator(
  target: 'username' | 'email' | 'phone',
  checker: (value: string) => boolean,
  userService: UserService
): AsyncValidatorFn {
  return (control: AbstractControl): Observable<NullableType<ValidationErrors>> => {
    if (!!control.value && checker(control.value)) {
      // We do get here, I've checked
      return timer(300).pipe<NullableType<ValidationErrors>>(
        switchMap<number, Observable<NullableType<ValidationErrors>>>(
          (): Observable<NullableType<ValidationErrors>> => {
            console.log('SwitchMap');// The whole callback is never called
            // Here I'm supposed to make an HTTP request instead of returning a null
            return of<null>(null);
          }
        )
      );
    }

    return of<null>(null);
  };
}

如果我将timer 替换为

of<string>(control.value).pipe<NullableType<ValidationErrors>>(delay(), switchMap.......)

它也不起作用。
如果我将 switchMap 替换为 switchMapOf 它可以工作,但没有去抖时间。

【问题讨论】:

  • 您想要timer 还是debounceTime?注意:请记住,如果您的输入有另一个同步验证器但未通过,则 asyncValidator 不会执行
  • 我需要的是,例如,如果用户键入“qwerty”,应用程序应该向 API 发送 1 个请求,而不是每个字符的 1 个请求。同步验证器已通过,但我尝试完全删除它们,没有任何改变。关于 timer / debounceTime - 看看主题的结尾,of / delay 选项对我来说似乎更合理,但也不起作用。添加 switchMap 后,Observable 似乎已停止订阅。

标签: angular typescript rxjs


【解决方案1】:

看看this SO

好吧,您可以像这样创建验证器:

checkIfNotRegister(): AsyncValidatorFn {
    return (control: AbstractControl): Promise<ValidationErrors | null> |
                                       Observable<ValidationErrors | null> => {
      return timer(1000).pipe(switchMap(_=>this.service.getWebName(control.value).pipe(
        map(res => res ? { repeat: "name yet register" } : null)
      )))

    };
  }

但是您在this forked stackblitz 中看到,每次输入更改都会显示消息“Validating..”-如果您将计时器更改 10000 毫秒,则此效果更明显-

【讨论】:

  • 这看起来和我上面的代码一模一样。我从来没有收到过回调 (_ =&gt; this.service.....)。
  • 在分叉的 stackblitz 中看起来像工作(如果您打开控制台,您会看到该服务只显示“最后一个”输入:(
  • 是的,我查过了。这就是讨论的主题 - 为什么至少有 2 个可行的解决方案在我的案例中没有给出预期的结果,以及我应该从哪里开始寻找问题。
猜你喜欢
  • 1970-01-01
  • 2019-03-12
  • 2017-11-30
  • 1970-01-01
  • 2017-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多