Max*_*icu 5 javascript typescript angular-material angular
我正在尝试找到一种更好的方法来处理复杂的角度形式。表格真的很大,我需要找到一种降低复杂性的方法。
这是表单结构的示例:
{
"fieldA" : ...,
"fieldB" : ...,
"fieldC" : ...,
"profile": {
"username": ...,
"email": ...,
"firstName": ...,
"lastName": ...,
...
},
"settings": {
"enableEmailNotification": ...,
"notificationsEmail": ..., // required when enableEmailNotification
...
},
...
}
Run Code Online (Sandbox Code Playgroud)
在某些情况下,验证器会随时更改,例如,当时enableEmailNotification=true,组件会将Required验证器添加到notificationsEmail
以下是研究的选项:
这种方法使用一种形式和一个组件。
优点:
缺点:
这种方法将formGroup其作为@Input()属性发送到内部组件。
优点:
缺点:
基于本文,我们可以创建自定义ControlValueAccessor,它将返回表单一部分的对象。
优点:
缺点:
我对于大型复杂表单的策略是拥有一个包装组件和子组件。每个子组件都有自己的表单服务,包装器有一个主表单服务,其中注入了子表单服务,请考虑这一点
@Component({
selector: 'form-wrapper',
template: `
<form [formGroup]="form" (submit)="save()">
<sub-form-a></sub-form-a>
<sub-form-b></sub-form-b>
<input type="submit" value="Submit Form">
</form>
`,
providers: [MasterFormService, FormAService, FormBService]
})
export class FormWrapper {
constructor(private formService: MasterFormService) { }
save() {
// whatever save actions here
}
}
@Component({ // form b compoent is basically the same
selector: 'sub-form-a',
template: `
... whatever template belongs to form a ..
`
})
export class FormAComponent {
form: FormGroup
constructor(private formService: FormAService) {
this.form = this.formService.form;
// form a specific actions
}
}
@Injectable()
export class MasterFormService {
form: FormGroup;
constructor(private fb: FormBuilder, formAService: FormAService, formBService: FormBService) {
this.form = this.fb.group({
groupA: this.formAService.form,
groupB: this.formBService.form,
});
}
}
@Injectable() // formB service is basically the same
export class FormAService {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
.. whatever fields belong to form a ..
});
}
}
Run Code Online (Sandbox Code Playgroud)
此方法创建高度可重用的子表单,并允许您模块化/隔离表单逻辑和模板。我经常发现子表单通常属于多个地方,因此它使我的代码非常干燥。特别是在您的示例中,您可以轻松地在应用程序的其他位置重用设置表单和配置文件表单组件。一两次我什至再次嵌套这个结构以形成极其复杂的形式。
缺点是结构可能看起来很复杂,但你很快就会习惯它。
就我个人而言,对于大型复杂表单,我希望将表单逻辑保留在一个组件中,因此很容易链接可观察量,但使用几个服务作为帮助程序。既用于初始化表单,又用于处理操作(返回新表单值、验证、授权等)
FormComponentFormInitServiceFormActionService(s)表单组件
export class FormComponent implements OnInit {
constructor(
private formActionService: FormActionService,
private formInitService: FormInitService
) { }
ngOnInit() {
this.form = this.FormInitService.getForm();
this._trackFieldA();
this._trackProfile();
}
// Track a single field
private _trackFieldA() {
this.form.controls.fieldA.valueChanges.pipe(
distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b))
).subscribe(fieldA => {
console.log('Field A Changed');
this.formActionService.doSomething();
});
}
// Track a group
// Use ['controls'] for nested controls to skip typechecking errors
private _trackProfile() {
combineLatest(
this.form.controls.profile['controls'].username.valueChanges,
this.form.controls.profile['controls'].email.valueChanges,
).pipe(
distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b))
).subscribe(profile => {
console.log('Some profile field changed');
this.formActionService.doSomething();
});
}
}
Run Code Online (Sandbox Code Playgroud)
表单初始化服务
export class FormInitService {
constructor(
private formBuilder: FormBuilder
) { }
public getForm(): FormGroup {
return this.formBuilder.group({
fieldA: 'Some init value',
fieldB: 'Some init value',
profile: this.formBuilder.group({
username: 'Some init value',
email: 'Some init value',
...
}),
...
});
}
}
Run Code Online (Sandbox Code Playgroud)
表单操作服务
export class FormActionService {
public doSomething(): any | void {
console.log('Something')
}
}
Run Code Online (Sandbox Code Playgroud)
FormComponent 和模板中仍然有相当多的代码,但它确实很容易阅读和维护。拆分为多个组件通常会变得非常混乱,特别是在团队中工作时,或者需要进行一些(巨大的)重构时。
| 归档时间: |
|
| 查看次数: |
217 次 |
| 最近记录: |