具有动态变化的子表单的复杂 Angular 表单
Complex Angular forms with dynamically changing sub-forms
这是来自 Google 日历的屏幕截图。如何在 Angular/Material(当前分别为 4.4.4 和 2.0.0-beta.12)中构建此界面?
注意:我发现 Angular 和 Material 有两个特别具有挑战性的功能。
整个表格根据第一个选择框而变化。 "Repeat daily" 计算天数,而 "repeat weekly" 提供一周中特定日期的复选框。 ("Repeat monthly" 也提供独特的选项。)我真的更喜欢模块化解决方案,我可以在其中将相互排斥的子表单分解为它们自己的 component/formGroup。在 ngIf 存在的情况下管理验证也让我头疼。
"Ends:" 块是一个组合单选按钮,带有用于某些选项的数字和日期输入。我不确定如何使用 angular+material 来近似,或者如何设置验证。我很乐意让 "Ends" 也成为一个选择框,但在那种情况下,我不想为后面的 0 或 1 个输入字段使用单独的 component/formGroup。所以我不能将它完全简化为问题 #1 的一个实例。
我不得不为一个应用程序构建相同的组件,虽然它基于 OSX 提醒计划程序,但大致相同。
最好只关注 "end" 选择,因为可以在整个组件中应用相同的概念。 end
FormGroup是一个更大的FormGroup中的一个控件,看起来像这样
end: this.fb.group({
// default to 'never'. Can also be 'date' or 'count'
selection: 'never',
// default the date to one week from now
date: [startOfDay(addDays(oneHourFromNow, 7)), Validators.required],
// default to only repeating once
count: [1, [Validators.required, CustomValidators.number(this.countLimits)]]
})
显然,如果您按原样提交此表单,它将包含一个没有多大意义的值。为了解决这个问题,您需要根据需要 enable
和 disable
date
和 count
控件。当抽象控件被禁用时,它不会包含在表单值中。
this.endGroup.get('selection').valueChanges
.startWith(null)
.subscribe(() => {
// if the selection value is 'never',
// disable both the 'date' and 'count' controls
// if the selection value is 'date',
// enable 'date' control and disable 'count' control
// if the selection value is 'count',
// enable 'count' control and disable 'date' control
});
结束选择器的模板看起来有点像这样,
<mat-select formControlName="selection">...</mat-select>
<ng-container *ngIf="selectionControl.value === 'date'">
<!-- input with datepicker -->
</ng-container>
<ng-container *ngIf="selectionControl.value === 'count'">
<!-- input with type="number" -->
</ng-container>
Todd Motto 的 This article 也帮助将表单组封装到它们自己的表示组件中。我很乐意解释更多,但这绝对是我必须构建的最复杂的组件,因此在一个答案中包含的内容有点多。
这是来自 Google 日历的屏幕截图。如何在 Angular/Material(当前分别为 4.4.4 和 2.0.0-beta.12)中构建此界面?
注意:我发现 Angular 和 Material 有两个特别具有挑战性的功能。
整个表格根据第一个选择框而变化。 "Repeat daily" 计算天数,而 "repeat weekly" 提供一周中特定日期的复选框。 ("Repeat monthly" 也提供独特的选项。)我真的更喜欢模块化解决方案,我可以在其中将相互排斥的子表单分解为它们自己的 component/formGroup。在 ngIf 存在的情况下管理验证也让我头疼。
"Ends:" 块是一个组合单选按钮,带有用于某些选项的数字和日期输入。我不确定如何使用 angular+material 来近似,或者如何设置验证。我很乐意让 "Ends" 也成为一个选择框,但在那种情况下,我不想为后面的 0 或 1 个输入字段使用单独的 component/formGroup。所以我不能将它完全简化为问题 #1 的一个实例。
我不得不为一个应用程序构建相同的组件,虽然它基于 OSX 提醒计划程序,但大致相同。
最好只关注 "end" 选择,因为可以在整个组件中应用相同的概念。 end
FormGroup是一个更大的FormGroup中的一个控件,看起来像这样
end: this.fb.group({
// default to 'never'. Can also be 'date' or 'count'
selection: 'never',
// default the date to one week from now
date: [startOfDay(addDays(oneHourFromNow, 7)), Validators.required],
// default to only repeating once
count: [1, [Validators.required, CustomValidators.number(this.countLimits)]]
})
显然,如果您按原样提交此表单,它将包含一个没有多大意义的值。为了解决这个问题,您需要根据需要 enable
和 disable
date
和 count
控件。当抽象控件被禁用时,它不会包含在表单值中。
this.endGroup.get('selection').valueChanges
.startWith(null)
.subscribe(() => {
// if the selection value is 'never',
// disable both the 'date' and 'count' controls
// if the selection value is 'date',
// enable 'date' control and disable 'count' control
// if the selection value is 'count',
// enable 'count' control and disable 'date' control
});
结束选择器的模板看起来有点像这样,
<mat-select formControlName="selection">...</mat-select>
<ng-container *ngIf="selectionControl.value === 'date'">
<!-- input with datepicker -->
</ng-container>
<ng-container *ngIf="selectionControl.value === 'count'">
<!-- input with type="number" -->
</ng-container>
Todd Motto 的 This article 也帮助将表单组封装到它们自己的表示组件中。我很乐意解释更多,但这绝对是我必须构建的最复杂的组件,因此在一个答案中包含的内容有点多。