首页 > 解决方案 > Angular Reactive Forms 使用服务中的 Observable 进行异步验证

问题描述

我在 Angular 8.3.4 中做一个 Web 应用程序。我有一个使用反应式表单的表单,我想添加异步验证以确保输入的名称是唯一的。我已经阅读了很多例子,但由于某种原因对我不起作用。

服务

export class BrandService {
  brands: Observable<BrandId[]>;
}

零件

export class CreateNewComponent {

  form: FormGroup;

  constructor(
    private formBuilder: FormBuilder,
    private brandService: BrandService
  ) {
    // Creates a form group
    this.form = this.formBuilder.group({
      name: ['', Validators.compose([
        Validators.required,
        Validators.minLength(6),
        CustomValidator.unique(this.brandService.brands)
      ])]
    });
  }
}

自定义验证器

export class CustomValidator {

  static unique(brands: Observable<BrandId[]>) {
    return (control: AbstractControl) => {

      const name = control.value.toLowerCase();

      return brands.pipe(
        map(items => items.filter(b => b.name.toLowerCase() === name)),
        map(items => items.length ? {unique: false} : null)
      );

    };
  }

}

我将服务的 Observable 从组件传递给 CustomValidator。现在,该控件具有:status: "INVALID"

顺便说一句,我应该在我的unique方法中明确返回什么?

我的目标是知道该名称是否已存在于 Observable 的数组中以返回控制错误。

标签: angularangular-reactive-forms

解决方案


异步验证器应通过另一个数组(或单独)传入,例如

name: [
  '', 
  Validators.compose([ Validators.required, Validators.minLength(6)]), 
  () => CustomValidator.unique(this.brandService.brands)
]

另请注意,它位于函数中,我早期发现的许多示例都bind本文一样使用,但我更喜欢使用函数。

------编辑 ------ 这是一个工作示例

@Component({
  selector: 'app-new',
  templateUrl: './new.component.html',
  styleUrls: ['./new.component.css']
})
export class NewComponent {

  form: FormGroup;

  constructor(
    private formBuilder: FormBuilder,
    private brandService: BrandService,
  ) {
    const brand = new BrandId();
    brand.name = 'abcdef';

    this.brandService.brands = of([brand]);
    // Creates a form group
    this.form = this.formBuilder.group({
      name: ['', Validators.compose([
        Validators.required,
        Validators.minLength(6),
      ]),
        (control) => CustomValidator.unique(this.brandService.brands, control)]
    });
  }
}

export class CustomValidator {
  static unique(brands: Observable<BrandId[]>, control: AbstractControl) {
    const name = control.value.toLowerCase();

    return brands.pipe(
      map(items => items.filter(b => b.name.toLowerCase() === name)),
      map(items => items.length ? { unique: false } : null)
    );

  }
}

推荐阅读