markAllAsTouched 和 markAsTouched 都不会影响子表单
Both markAllAsTouched and markAsTouched don't affect subforms
背景资料
我有一个 非常 的大表单(可能有数百个字段),我决定将其分解为更小的子表单组件(出于显而易见的原因)。我使用控制值访问器实现了这一点。在提交时显示字段错误之前,这一直很有效。
子表单的结构如下:
<form [formGroup]="form">
<app-subform [documentId]="documentId" formControlName="sub-form"></app-subform>
<!-- Other form fields here ... -->
</form>
为了简化我的工作,我创建了一个错误组件,它将一个控件作为输入,如下面的代码所示。下面的代码是子表单的一部分。
<div class="question">
<label for="tableNumber">
Figure/table number
<app-required [type]="'conditional'"></app-required>
</label>
<input type="text" id="tableNumber" formControlName="figure"/>
<app-error [control]="form.get('figure')"></app-error>
</div>
我的错误 HTML 的内部看起来像这样:
<span class="errorWrapper" *ngIf="control.invalid && control.touched" (click)="clearError()" [innerHtml]="error"></span>
示例代码
虽然我不能完全分享我的完整代码,但这里是问题的重现:
https://stackblitz.com/edit/encapsulated-sub-forms
问题
当我提交我的代码时,为了在每个输入中显示错误消息,我使用 this.form.markAllAsTouched();
将所有输入标记为已触摸。虽然这对于不属于子表单组件的输入来说就像一个魅力,但子表单组件本身根本没有反应,保持不变。
我考虑过的解决方案
- 我的第一反应是 - 为什么不将每个控件单独标记为已触摸? 不起作用
- 我如何为触发标记为触摸的每个子表单组件实现一个输入? 没有尝试,看起来更像是 hack 而不是最佳实践解决方案
- 更改我的实现以使用
ControlContainer
。 似乎最有希望
我试过的
我尝试将实现更改为使用 ControlContainer
,但这带来了一系列挑战(在单独的堆栈溢出问题中描述)。
我的问题
所以基本上,我想知道的是,如何让我的子表单输入在提交时显示错误,遵循最佳实践并进行最少的重写(我的优先顺序是这样的)?
这里的问题是您的子表单组件正在声明一个全新的 FormGroup
实例。它对父控件中的 FormGroup
实例一无所知。
我的方法是将根 FormGroup
中的嵌套表单组从父表单传递到子表单。
这将允许您的子表单更新父表单中的表单组,而无需双向绑定。并且在表单组上触发的事件将通过子表单传播。
示例代码
parent.component.ts
this.form = this.formBuilder.group({
subGroup1: this.formBuilder.group({}),
subGroup1: this.formBuilder.group({})
});
parent.component.html
<form [formGroup]="form">
<app-sub-form-1 [form]="form.get('subGroup1')"></app-sub-form-1>
<app-sub-form-2 [form]="form.get('subGroup2')"></app-sub-form-1>
</form>
亚form1.component.ts
this.form.addControl('sub-group1-control1', new FormControl(''));
符合逻辑,触摸的控件是form.get('subForm')
。
抱歉,我找不到好的解决方案。我永远不明白为什么在更容易使用组件时创建自定义表单控件,请参见,例如this SO or this post from Tomas Trajan
我建议这个方法,否则你需要在每个自定义表单控件中创建一个方法来标记所有被触摸并从父级调用
背景资料
我有一个 非常 的大表单(可能有数百个字段),我决定将其分解为更小的子表单组件(出于显而易见的原因)。我使用控制值访问器实现了这一点。在提交时显示字段错误之前,这一直很有效。
子表单的结构如下:
<form [formGroup]="form">
<app-subform [documentId]="documentId" formControlName="sub-form"></app-subform>
<!-- Other form fields here ... -->
</form>
为了简化我的工作,我创建了一个错误组件,它将一个控件作为输入,如下面的代码所示。下面的代码是子表单的一部分。
<div class="question">
<label for="tableNumber">
Figure/table number
<app-required [type]="'conditional'"></app-required>
</label>
<input type="text" id="tableNumber" formControlName="figure"/>
<app-error [control]="form.get('figure')"></app-error>
</div>
我的错误 HTML 的内部看起来像这样:
<span class="errorWrapper" *ngIf="control.invalid && control.touched" (click)="clearError()" [innerHtml]="error"></span>
示例代码
虽然我不能完全分享我的完整代码,但这里是问题的重现: https://stackblitz.com/edit/encapsulated-sub-forms
问题
当我提交我的代码时,为了在每个输入中显示错误消息,我使用 this.form.markAllAsTouched();
将所有输入标记为已触摸。虽然这对于不属于子表单组件的输入来说就像一个魅力,但子表单组件本身根本没有反应,保持不变。
我考虑过的解决方案
- 我的第一反应是 - 为什么不将每个控件单独标记为已触摸? 不起作用
- 我如何为触发标记为触摸的每个子表单组件实现一个输入? 没有尝试,看起来更像是 hack 而不是最佳实践解决方案
- 更改我的实现以使用
ControlContainer
。 似乎最有希望
我试过的
我尝试将实现更改为使用 ControlContainer
,但这带来了一系列挑战(在单独的堆栈溢出问题中描述)。
我的问题
所以基本上,我想知道的是,如何让我的子表单输入在提交时显示错误,遵循最佳实践并进行最少的重写(我的优先顺序是这样的)?
这里的问题是您的子表单组件正在声明一个全新的 FormGroup
实例。它对父控件中的 FormGroup
实例一无所知。
我的方法是将根 FormGroup
中的嵌套表单组从父表单传递到子表单。
这将允许您的子表单更新父表单中的表单组,而无需双向绑定。并且在表单组上触发的事件将通过子表单传播。
示例代码
parent.component.ts
this.form = this.formBuilder.group({
subGroup1: this.formBuilder.group({}),
subGroup1: this.formBuilder.group({})
});
parent.component.html
<form [formGroup]="form">
<app-sub-form-1 [form]="form.get('subGroup1')"></app-sub-form-1>
<app-sub-form-2 [form]="form.get('subGroup2')"></app-sub-form-1>
</form>
亚form1.component.ts
this.form.addControl('sub-group1-control1', new FormControl(''));
符合逻辑,触摸的控件是form.get('subForm')
。
抱歉,我找不到好的解决方案。我永远不明白为什么在更容易使用组件时创建自定义表单控件,请参见,例如this SO or this post from Tomas Trajan
我建议这个方法,否则你需要在每个自定义表单控件中创建一个方法来标记所有被触摸并从父级调用