【问题标题】:Angular Reactive Forms Async Validation using an Observable from ServiceAngular Reactive Forms 使用服务中的 Observable 进行异步验证
【发布时间】:2019-10-01 14:18:40
【问题描述】:

我正在使用 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 的数组中以返回控制错误。

【问题讨论】:

  • 异步验证器必须实现 AsyncValidator,参见angular.io/guide/…。注意:你总是可以在提交调用到你的 observable 并显示一条消息它不是唯一的

标签: angular angular-reactive-forms


【解决方案1】:

异步验证器应该通过另一个数组(或它自己)传入,类似于

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

还要注意它在函数中,我早期发现的许多示例都使用bind,例如in this article,但我更喜欢使用函数。

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

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

  }
}

【讨论】:

  • 这是我唯一需要的改变吗?根据上面Eliseo的回答,我需要实现AsyncValidator,这个实现是必须的还是用你的解决方案就够了?
  • 在我的测试中,只要你返回 null 它就不会显示错误。您返回的错误对象看起来应该可以工作。
  • 实际上,我收回了这一点。尝试返回 {unique: true}。那时您可能希望从唯一重命名。
  • 由于某种原因,仍然不适合我。控件/表单一直保持status: "INVALID"
  • 您好,我的朋友,我已经尝试过您的新解决方案,但是它对我不起作用。该字段不会触发错误消息,我无法判断输入的值是否唯一。我不知道发生了什么。
猜你喜欢
  • 2017-01-17
  • 2022-06-10
  • 1970-01-01
  • 1970-01-01
  • 2021-08-30
  • 2018-08-09
  • 1970-01-01
  • 1970-01-01
  • 2017-03-10
相关资源
最近更新 更多