问题描述
我正在构建一个反应式角度表单,我正在尝试找到一种方法来触发所有验证器提交.如果验证器是同步的,那就没问题了,因为我可以在线获取它的状态.否则,如果验证器是异步验证器并且尚未触发,则 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
发出表单提交,您可以 switchMap
到 form.statusChange
和 filter
结果.
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)
确保流在待处理后的第一次发射时完成:VALID
或 INVALID
.
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 表单等待异步验证器在提交时完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!