我们能不能把一个反应式表单分割成多个组件?
例如,父组件中的按钮(SAVE、UPDATE和DELETE)和表单放在子组件中。
如何实现这个功能?
有什么例子吗?
有什么例子吗?
你可以将一个反应式表单分割成多个子表单,但是你需要利用ControlValueAccessor和它的朋友,你需要将它嵌套在一个父表单中,从那里提交。当然,你还需要添加一些额外的模板,以便拥有所有的验证和反应式表单所需要的其他一切。
你可以通过这种方式拥有任意多的子表单。
下面你可以看到一个例子,说明你如何用Angular的方式来实现它。
子组件
import { Component, OnInit, forwardRef } from '@angular/core';
import {
NG_VALUE_ACCESSOR,
NG_VALIDATORS,
ControlValueAccessor,
Validator,
FormGroup,
FormBuilder,
AbstractControl,
ValidationErrors,
Validators
} from '@angular/forms';
@Component({
...
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => ChildComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => ChildComponent),
multi: true
}
]
})
export class ChildComponent implements OnInit, ControlValueAccessor, Validator {
public childForm: FormGroup;
public onTouched: () => void = () => {};
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
this.childForm = this.fb.group({
...
});
}
public writeValue(val: any): void {
return val && this.childForm.setValue(val, { emitEvent: false });
}
public registerOnChange(fn: any): void {
this.childForm.valueChanges.subscribe(fn);
}
public registerOnTouched(fn: any): void {
this.onTouched = fn;
}
public setDisabledState?(isDisabled: boolean): void {
isDisabled ? this.childForm.disable() : this.childForm.enable();
}
public validate(control: AbstractControl): ValidationErrors | null {
return this.childForm.valid
? null
: { invalidForm: { valid: false, message: 'Form is invalid' } };
}
}
子组件模板。
<ng-container [formGroup]="childForm">
.....
</ng-container>
父组件 ts
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';
@Component({
...
})
export class StandardSetupFormComponent implements OnInit {
parentForm: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
this.parentForm = this.fb.group({
child: null,
...
});
}
public onSubmit() {
...
}
}
父组件模板。
<form class="form" [formGroup]="parentForm" (ngSubmit)="onSubmit()">
<app-child formControlName="child"></app-child>
<button[disabled]="parentForm.invalid">Submit</button>
</form>
如你所见,在父组件中,你需要将子表单作为一个表单控件。
还有其他的方法可以做到这一点。例如通过使用输入,即使它看起来更简单,它也不是正确的方式。
我前段时间看过一篇很好的文章,讲的就是我上面给你展示的内容,但是我现在还找不到。如果找到了我会更新答案的。
喏,这里 是文章,让你对嵌套反应式表单有更好更深的理解。
过去我在做这个事情的时候,一般会用服务来管理和发布表单。
@Injectable()
export class MyFormService {
private _form: FormGroup;
constructor(private fb: FormBuilder) {
this.buildForm()
}
private buildForm() {
this._form = this.fb.group({
// whatever form specifics in here
})
}
get form() {
return this._form
}
// whatever of these you need
get childForm() {
return this.form.get('childFormKey')
}
// any other appropriate methods or observables exposed
}
父组件。
@Component({
.. component stuff ..
providers: [MyFormService] // might as well provide it here to keep it private
})
export class ParentComponent {
constructor(private formService: MyFormService) {
}
onSubmit() {
const value = this.formService.form.value;
// do the submit
}
// any methods you need
}
子组件:
export class ChildComponent {
childForm: FormGroup
constructor(private formService: MyFormService) {
this.childForm = this.formService.childForm;
// do whatever else you need for this component
}
}
这种方法最适用于大的复杂表单,你想把它分解成较小的不太复杂的表单,但这些东西不会有很高的可重用性(尽管你仍然可以用这种方法得到很好的可重用性,如果你设置正确的话)。 它也很适合你想要相同的整体表单,但不同模板的情况。
那些更像 "widget "的东西,而且你打算在许多表单中使用,可能会需要一种不同的方法。