如何强制以角反应形式的场重新运行验证

时间:2019-09-30 19:21:18

标签: angular angular-reactive-forms

我正在将Angular用于反应形式和材料UI。我有一个表单,其中有一个文本字段,仅当另一个字段具有某个值时才需要该文本字段-例如,仅选择一个单选按钮时,文本输入才出现并且是必需的。这是一个示例代码片段:

<div>
    Do you have any concerns?
</div>
<mat-radio-group formControlName="haveConcerns">
    <mat-radio-button [value]=true>yes</mat-radio-button>
    <mat-radio-button [value]=false>no</mat-radio-button>
</mat-radio-group>
<div [hidden]="!form.value.haveConcerns">
    <div>
        if "YES", please list the reasons:`enter code here`
    </div>
    <mat-form-field>
        <input formControlName="concerns" matInput placeholder="reasons" type="text">
        <mat-error *ngIf="hasError(this.form, 'concerns', 'maybeRequired')">
            please explain any concerns your may have
        </mat-error>
    </mat-form-field>
</div>

我的问题是,第一次绘制表单时会调用验证,并且该验证通过了,因为未选中该按钮。但是,当用户单击单选按钮时,由于该字段未更改,因此不会重新运行其验证。

现在,我正在手动将担忧字段的值设置为其自身,以使验证重新运行,但是感觉就像是黑客。

public applyForm(formValue) {
    this.formIsSubmitted = true;
    const concernsField= this.form.get('concerns');
    concernsField.setValue(concernsField.value);
    if (this.form.valid) {
        this.submitFormValue(formValue);
    }
}

有更好的方法吗?如果我有一个大表格,这将变得很笨拙。我看到有一个setDirty方法,但是我在窗体和控件上都尝试了它,但它似乎没有做任何事情。

1 个答案:

答案 0 :(得分:2)

如果您的表单很大,我将为彼此依赖的控件创建一个嵌套的表单组,然后在该嵌套的表单上附加自定义验证器。例如:

this.form = this.fb.group({
  nested: this.fb.group(
    {
      haveConcerns: [false],
      concerns: [""]
    },
    { validators: concernValidator }
  )
});

,然后在任何一个formcontrol值更改时将触发它。

DEMO HERE

您当然也可以在主表单上附加验证器,但是如果表单很大,则在编辑无关字段时会不必要地触发。

如果执行此操作,则需要创建自定义错误状态匹配器,因为如果表单组有错误,则仅在formcontrol发生错误时才显示mat-error here 。可以找到如何为此目的创建自定义错误状态匹配器。


如您所注意到的,如果您真的只想在concerns表单控件上使用验证器,则无论何时haveConcerns发生变化,都必须以某种方式触发对该表单控件的验证。您可以通过侦听该表单控件的valueChanges(或仅侦听更改的函数)并调用this.form.get('concerns).updateValueAndValidity()来实现此目的,这将触发该字段的自定义验证器,例如:

this.form.get("haveConcerns").valueChanges.subscribe(data => {
  this.form.get('concerns').updateValueAndValidity();
});

如果这样做,请记住退订组件OnDestroy