响应式 Angular 表单等待异步验证器在提交时完成 [英] Reactive Angular form to wait for async validator complete on submit

查看:30
本文介绍了响应式 Angular 表单等待异步验证器在提交时完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个反应式角度表单,我正在尝试找到一种方法来触发所有验证器提交.如果验证器是同步的,那就没问题了,因为我可以在线获取它的状态.否则,如果验证器是异步验证器并且尚未触发,则 ngSubmit 方法上的表单将处于待处理状态.我试图注册表单 statusChange 属性的订阅,但是当我使用 markAsTouched 函数手动调用验证时,它没有被触发.

I am building a reactive angular form and I'm trying to find a way to trigger all validators on submit. If the validor is a sync one, it'd be ok, as I can get the status of it inline. Otherwise, if the validator is an async one and it was not triggered yet, the form on ngSubmit method would be in pending status. I've tried to register a subscribe for the form statusChange property, but it's not triggered when I call for validation manualy with markAsTouched function.

这里有一些片段:

   //initialization of form and watching for statusChanges
   ngOnInit() {
        this.ctrlForm = new FormGroup({
            'nome': new FormControl('', Validators.required),
            'razao_social': new FormControl('', [], CustomValidators.uniqueName),
            'cnpj': new FormControl('', CustomValidators.cnpj),
        });

        this.ctrlForm.statusChanges.subscribe(
            x => console.log('Observer got a next value: ' + x),
            err => console.error('Observer got an error: ' + err),
            () => console.log('Observer got a complete notification')
        )
    }
    //called on ngSubmit
    register(ctrlForm: NgForm) {
            Forms.validateAllFormFields(this.ctrlForm);
            console.log(ctrlForm.pending); 
            //above will be true if the async validator
            //CustomValidators.uniqueName was not called during form fill.
    }
    //iterates on controls and call markAsTouched for validation,
    //which doesn't fire statusChanges
    validateAllFormFields(formGroup: FormGroup) {         
          Object.keys(formGroup.controls).forEach(field => {  
              const control = formGroup.get(field);             
              if (control instanceof FormControl) {             
                control.markAsTouched({ onlySelf: true });
              } else if (control instanceof FormGroup) {        
                this.validateAllFormFields(control);            
              }
          });
      }

关于如何确保异步验证器已执行以便我可以继续触发并完成所有验证器的寄存器逻辑的任何想法?

Any ideas on how can I ensure that the async validator was executed so I can continue with the register logic having all validators triggered and completed?

推荐答案

Angular 在触发 ngSubmit 之前不会等待异步验证器完成.因此,如果验证器未解析,则表单可能无效.

Angular doesn't wait for async validators to complete before firing ngSubmit. So the form may be invalid if the validators have not resolved.

使用 Subject 来发出表单提交,您可以 switchMapform.statusChangefilter 结果.

Using a Subject to emit form submissions, you can switchMap to form.statusChange and filter the results.

startWith 开头,以确保没有悬挂发射,以防表单在提交时有效.

Begin with a startWith to ensure there's no hanging emission, in the case the form is valid at the time of submission.

PENDING 过滤等待此状态更改,take(1) 确保流在待处理后的第一次发射时完成:VALIDINVALID.

Filtering by PENDING waits for this status to change, and take(1) makes sure the stream is completed on the first emission after pending: VALID or INVALID.

//
// <form (ngSubmit)="formSubmitSubject$.next()">

this.formSubmitSubject$ = new Subject();

this.formSubmitSubject$
  .pipe(
    tap(() => this.form.markAsDirty()),
    switchMap(() =>
      this.form.statusChanges.pipe(
        startWith(this.form.status),
        filter(status => status !== 'PENDING'),
        take(1)
      )
    ),
    filter(status => status === 'VALID')
  )
  .subscribe(validationSuccessful => this.submitForm());

您还可以添加一个 tap 来触发将表单设置为脏的副作用.

You can also add a tap that triggers the side effect of settings the form as dirty.

这篇关于响应式 Angular 表单等待异步验证器在提交时完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆