结合使用rxjs SwitchMap和Async FormControl Validator

时间:2019-07-31 16:39:49

标签: angular rxjs

我正在尝试将SwitchMap与异步验证程序结合使用,我创建了以下异步验证程序,但先前请求的SwitchMap取消行为无效!

我在这里缺少什么?

static emailValidator(userService: UsersService) {
    return (control: AbstractControl) => {
      return of(control.value).pipe(
        switchMap(
          value => userService.validateEmail(value)
        ),
        map(
          (res: {isValid: boolean}) => {
            return res.isValid ? null : {username: false};
          }
        ),
        catchError(
          (err) => {
            return of({username: false});
          }
        )
      );
    };
  }

2 个答案:

答案 0 :(得分:0)

您每次都在创建一个新的可观察对象,因此源不再发射,因此也不会切换。无论如何,这都是多余的,因为异步验证器会自动处理取消操作,只需执行以下操作:

static emailValidator(userService: UsersService) {
    return (control: AbstractControl) => {
      return userService.validateEmail(control.value).pipe(
        map(
          (res: {isValid: boolean}) => {
            return res.isValid ? null : {username: false};
          }
        ),
        catchError(
          (err) => {
            return of({username: false});
          }
        )
      );
    };
  }

闪电战证明了这一点:https://stackblitz.com/edit/angular-xqjgbe?file=src/app/app.component.ts

如果您想完全避免使用新值发送请求(将其反跳)...这很容易;

static emailValidator(userService: UsersService) {
    return (control: AbstractControl) => {
      return timer(300).pipe( // timer will debounce for you
        switchMapTo(userService.validateEmail(control.value)),
        map(
          (res: {isValid: boolean}) => {
            return res.isValid ? null : {username: false};
          }
        ),
        catchError(
          (err) => {
            return of({username: false});
          }
        )
      );
    };
  }

答案 1 :(得分:0)

您需要使用of(control.value)来代替使用control.valueChanges创建可观察对象:

static emailValidator(userService: UsersService) {
    return (control: AbstractControl) => {
      return control.valueChanges.pipe(
        switchMap(
          value => userService.validateEmail(value)
        ),
        map(
          (res: {isValid: boolean}) => {
            return res.isValid ? null : {username: false};
          }
        ),
        catchError(
          (err) => {
            return of({username: false});
          }
        )
      );
    };
  }