我有一个表单组,其中不同的窗体控件相互链接。每个窗体控件只有在已填充前一个窗体控件时才启用。另外,如果清除了一个窗体控件,那么所有下一个窗体控件都应该被清除和禁用。
我做了一个小小的例子来解释用例。在我的示例中,我处理四个窗体控件,而在实际用例中,我有更多的窗体控件。我不认为这个实现是优雅的,也不是很好的扩展。你有更好的实现吗?
export class AppComponent implements OnInit {
public myForm: FormGroup;
constructor(private fb: FormBuilder) {}
public ngOnInit(): void {
this.myForm = this.getMyForm();
this.handleFormValueChanges(this.myForm);
}
private getMyForm(): FormGroup {
return this.fb.group({
company: null,
country: [{
value: null,
disabled: true
}],
user: [{
value: null,
disabled: true
}],
adress: [{
value: null,
disabled: true
}]
});
}
/**
* Handle myForm value changes (didn't handle unsubscriptions because it is just an example)
* TODO: Find another implementation
*/
private handleFormValueChanges(form: FormGroup): void {
form.get("company").valueChanges.subscribe((value: string) => {
if (!value) {
form.get("country").reset();
form.get("country").disable();
form.get("user").reset();
form.get("user").disable();
form.get("adress").reset();
form.get("adress").disable();
} else {
form.get("country").enable();
}
});
form.get("country").valueChanges.subscribe((value: string) => {
if (!value) {
form.get("user").reset();
form.get("user").disable();
form.get("adress").reset();
form.get("adress").disable();
} else {
form.get("user").enable();
}
});
form.get("user").valueChanges.subscribe((value: string) => {
if (!value) {
form.get("adress").reset();
form.get("adress").disable();
} else {
form.get("adress").enable();
}
});
}
}
编辑:我最终实现了Fabio Carpinato的解决方案的一些变化
import { Component, OnInit, ChangeDetectionStrategy } from "@angular/core";
import { FormGroup, FormBuilder } from "@angular/forms";
import { merge } from "rxjs";
@Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent implements OnInit {
public myForm: FormGroup;
constructor(private fb: FormBuilder) {}
public ngOnInit(): void {
this.myForm = this.getMyForm();
this.handleFormValueChanges(this.myForm);
}
private getMyForm(): FormGroup {
return this.fb.group({
company: null,
country: [{ value: null, disabled: true }],
user: [{ value: null, disabled: true }],
adress: [{ value: null, disabled: true }]
/*
... other formcontrols
*/
});
}
/**
* Handle myForm value changes (didn't handle unsubscriptions nor debounceTime because it is just an example)
*/
private handleFormValueChanges(form: FormGroup): void {
const controlDisabledDependencies: { [controlKey: string]: string } = {
company: null,
country: "company",
user: "country",
adress: "user"
};
merge(
...Object.keys(controlDisabledDependencies).map(
(controlKey: string) => form.get(controlKey).valueChanges
)
).subscribe(() => {
Object.keys(controlDisabledDependencies).forEach((controlKey: string) => {
if (
form.get(controlDisabledDependencies[controlKey]) &&
!form.get(controlDisabledDependencies[controlKey]).value
) {
form.get(controlKey).disable({ emitEvent: false, onlySelf: true });
form
.get(controlKey)
.reset(null, { emitEvent: false, onlySelf: true });
} else {
form.get(controlKey).enable({ emitEvent: false, onlySelf: true });
}
});
});
}
}
发布于 2020-08-04 10:26:35
您可以通过创建依赖关系映射来简化这一点。
例如,地址取决于国家。所以你可以在你的地图上添加这样的东西:
map =‘地址’=> 'country‘
其中您使用的键是窗体控件的键。
然后,您可以做的是订阅表单值更改,每次输入订阅时,您都将遍历所有窗体控件键,并开始检查值,然后根据依赖关系映射决定禁用什么。
这变得很容易扩展,因为您可以在表单控件中添加依赖项,而不需要更改逻辑,您只需要向映射添加一个记录。
我为您编写了一个简单的https://stackblitz.com/edit/angular-ivy-qxfkdz示例。
发布于 2020-08-04 11:06:32
由于表单的顺序性,您的方法可能仍然是您所概述的场景中最好的方法。
但是,另一种方法是直接在表单本身上调用.valueChanges(),而不是单独的表单控件。这将为您提供一个父窗体对象,该对象将在任何嵌套窗体控件更改时发出。然后,您可以将您的逻辑合并到一个订阅调用中。
form.valueChanges.subscribe((value: any) => {
if (!value.company) {
form.get("country").reset({ emitEvent: false });
form.get("country").disable({ emitEvent: false });
} else {
form.get("country").enable({ emitEvent: false });
}
if (!value.country) {
form.get("user").reset({ emitEvent: false });
form.get("user").disable({ emitEvent: false });
} else {
form.get("user").enable({ emitEvent: false });
}
...
});注意:{ emitEvent: false }将阻止窗体触发对其自身的更改检测。这一点很重要,因为如果不这样做,您将陷入无限的更新循环。
由于您的设计形成了一种FormControls链,并且每个if语句实际上都会在链的每个元素上重复,所以我可能会倾向于让getMyForm()返回一个FormArray而不是一个FormGroup。这将允许您对FormControls进行迭代,就像它们存储在数组中一样,并将相同的函数应用于每个函数,这将更有效地扩展。对于FormGroup来说,这有点混乱(但仍然有可能)。
https://stackoverflow.com/questions/63244747
复制相似问题