响应形式的Angular2通用异步验证器

时间:2020-03-31 07:46:14

标签: javascript angular

我有一个反应式表单和一个必须唯一的表单控件:

this.form = new FormGroup({
  name: new FormControl(this.initialValue, [
    Validators.required,
  ], this._uniqueNameValidator.bind(this)),
});

我编写了一个异步验证程序,该验证程序从我的应用程序服务中调用一个方法:

private _uniqueNameValidator(control: FormControl) {
    const value = control.value.trim();
    if (value === '' || value === this.initialValue) {
      return of(null);
    }
    control.markAsTouched();
    return timer(500).pipe(
      switchMap(() => {
        return this._appService.validateName(value, this.selectedGroupId);
      }),
      map(response => {
        return response ? {nameTaken: true} : null;
      }),
      catchError(() => {
        return of(null);
      })
    );
 }

服务方法是一个简单的http GET,它返回一个boolean值:

validateName(name: string, groupId: number): Observable<boolean> {
 // ...
 return this._http.get<boolean>(url);
}

工作示例:https://stackblitz.com/edit/angular-8kedup

现在,在我的应用中,还有许多其他形式的控件必须是唯一的。异步检查唯一性,但是在其他服务方法和其他路由中。 我不想在每个需要异步验证器以确保唯一性的组件中复制验证器的代码。

问题: 我想编写一个通用的验证器,该验证器将必须调用的服务方法作为参数,以确定该值是否唯一以及初始表单值。

我编写了以下函数:

export function UniqueAsyncValidator(fn: any, initialValue: string): AsyncValidatorFn {
  return (control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
    const value = control.value.trim();
    if (value === '' || value === initialValue) {
      return of(null);
    }
    control.markAsTouched();
    return timer(500).pipe(
      switchMap(() => {
        return fn(value);
      }),
      map(response => {
        return response ? {nameTaken: true} : null;
      }),
      catchError(() => {
        return of(null);
      })
    );
  };
}

以及表单定义:

    this.form = new FormGroup({
      name: new FormControl(this.initialValue, [
        Validators.required,
        ], UniqueAsyncValidator(this._appService.validateName, this.initialValue).bind(this)),
   });

似乎已调用服务方法,但服务方法中的上下文(this)未定义:

validateName(name: string, groupId: number): Observable<boolean> {
  // ....
  console.log( 'this: ', this );  // -> returns undefined 
  return this._http.get<boolean>(url);
}

示例:https://stackblitz.com/edit/angular-sbbgc8

谢谢!

1 个答案:

答案 0 :(得分:2)

在两个版本中您不会进行相同的函数调用。您的服务功能需要groupId。您应该在回调中使用此arg调用服务。

const uniqueValidator = UniqueAsyncValidator(
  value => this._appService.validateName(value, this.selectedGroupId), 
  this.initialValue).bind(this);

this.form = new FormGroup({
  name: new FormControl(this.initialValue, [
    Validators.required,
  ], uniqueValidator)
});

创建UniqueAsyncValidator的实例时,您正在传递回调。这样,您就可以重用验证器中的逻辑,并注入将进行调用的函数。

value => this._appService.validateName(value, this.selectedGroupId)

这是箭头函数语法。它只是在声明一个匿名函数,该函数接受一个参数-value(这将由您的验证程序传递)-并返回this._appService.validateName(value, this.selectedGroupId)

演示:https://stackblitz.com/edit/angular-ynmzyu

相关问题