形式中的形式。表单控件可以继承吗?
Form in form. Can there be inheritance of form controls?
我有两个组件:ParentComponent 和 ChildComponent:
parent.component.ts
<form #form="ngForm" (ngSubmit)="onSubmit(form)" novalidate>
<input type="text" name="firstControl" [(ngModel)]="firstControl" />
<input type="text" name="secondControl" [(ngModel)]="secondControl" />
<child-component>
</form>
{{form.value | json}}
child.component.ts
<input type="text" name="thirdControl" [(ngModel)]="thirdControl" />
<input type="text" name="fourthControl" [(ngModel)]="fourthControl" />
现在,{{form.value | json}}
returns { "firstControl": "", "secondControl": "" }
很清楚了。我的问题是:有没有办法从子组件中继承表单控件?为 ParentComponent 获取 { "firstControl": "", "secondControl": "", "thirdControl": "", "fourthControl": "" }
的正确方法是什么?可能吗?
更新:
确实有一个更简单的方法:
import { FormsModule, ControlContainer, NgForm, NgModel } from '@angular/forms';
@Component({
...
viewProviders: [ { provide: ControlContainer, useExisting: NgForm } ]
})
export class ChildComponent {}
另见
- Angular2 nested template driven form
上一版本:
我会说这是可能的。例如,您可以将以下代码添加到您的
child.component.ts
import { NgForm, NgModel } from '@angular/forms';
@Component({
selector: 'child-component',
template: `
<input type="text" name="thirdControl" [(ngModel)]="thirdControl" />
<input type="text" name="fourthControl" [(ngModel)]="fourthControl" />
`
})
export class ChildComponent {
@ViewChildren(NgModel) ngModels: QueryList<NgModel>;
constructor(@Optional() private ngForm: NgForm) {}
ngAfterViewInit() {
if (this.ngForm) {
this.ngModels.forEach(model => this.ngForm.addControl(model));
}
}
}
Angular DI 系统使我们有机会获得对父 NgForm
实例的引用,因为 angular 依赖项解析算法从当前节点开始并向上遍历元素树。在我的示例中,我们可以想象下面的树
@NgModule providers
|
my-app
|
form
/ | \
input[text] input[text] child-component
所以当我们需要 NgForm
令牌时 angular 将在下一个顺序中搜索它
child-component
||
\/
form
||
\/
my-app
||
\/
@NgModule
在表单元素上放置了 NgForm
指令,以便何时可以获取它。我们还可以获得在 providers
数组中的 NgForm
指令上声明的任何标记。这条规则适用于任何节点。
另见
然后我将子 NgModel
指令手动添加到 NgForm
以便它们可以一起工作。
Angular有两种形式,Template Driven和Reactive。模板驱动表单无法实现您想做的事情,您需要查看 Reactive Forms
一般来说,它的工作原理是在组件中创建一个表单 object,然后在模板中使用它。 Angular 说这实际上更灵活,更容易测试,但我认为语法更难理解。
您需要在 parent 组件中使用:
myForm: FormGroup;
constructor(private fb: FormBuilder) { // <--- inject FormBuilder
this.createForm();
}
createForm() {
this.myForm = this.fb.group({
firstControl: '',
secondControl: '',
thirdControl: '',
fourthControl: ''
});
}
您的 parent 模板将如下所示:
<form [formGroup]="myForm" novalidate>
<input type="text"formControlName="firstControl" />
<input type="text" formControlName="secondControl" />
<child-component [parentFormGroup]="myForm">
</form>
并且您的 child 将接受表单组作为输入,模板将如下所示:
<div class="form-group" [formGroup]="parentFormGroup">
<input type="text" formControlName="thirdControl" />
<input type="text" formControlName="fourthControl" />
</div>
我有两个组件:ParentComponent 和 ChildComponent:
parent.component.ts
<form #form="ngForm" (ngSubmit)="onSubmit(form)" novalidate>
<input type="text" name="firstControl" [(ngModel)]="firstControl" />
<input type="text" name="secondControl" [(ngModel)]="secondControl" />
<child-component>
</form>
{{form.value | json}}
child.component.ts
<input type="text" name="thirdControl" [(ngModel)]="thirdControl" />
<input type="text" name="fourthControl" [(ngModel)]="fourthControl" />
现在,{{form.value | json}}
returns { "firstControl": "", "secondControl": "" }
很清楚了。我的问题是:有没有办法从子组件中继承表单控件?为 ParentComponent 获取 { "firstControl": "", "secondControl": "", "thirdControl": "", "fourthControl": "" }
的正确方法是什么?可能吗?
更新:
确实有一个更简单的方法:
import { FormsModule, ControlContainer, NgForm, NgModel } from '@angular/forms';
@Component({
...
viewProviders: [ { provide: ControlContainer, useExisting: NgForm } ]
})
export class ChildComponent {}
另见
- Angular2 nested template driven form
上一版本:
我会说这是可能的。例如,您可以将以下代码添加到您的
child.component.ts
import { NgForm, NgModel } from '@angular/forms';
@Component({
selector: 'child-component',
template: `
<input type="text" name="thirdControl" [(ngModel)]="thirdControl" />
<input type="text" name="fourthControl" [(ngModel)]="fourthControl" />
`
})
export class ChildComponent {
@ViewChildren(NgModel) ngModels: QueryList<NgModel>;
constructor(@Optional() private ngForm: NgForm) {}
ngAfterViewInit() {
if (this.ngForm) {
this.ngModels.forEach(model => this.ngForm.addControl(model));
}
}
}
Angular DI 系统使我们有机会获得对父 NgForm
实例的引用,因为 angular 依赖项解析算法从当前节点开始并向上遍历元素树。在我的示例中,我们可以想象下面的树
@NgModule providers
|
my-app
|
form
/ | \
input[text] input[text] child-component
所以当我们需要 NgForm
令牌时 angular 将在下一个顺序中搜索它
child-component
||
\/
form
||
\/
my-app
||
\/
@NgModule
在表单元素上放置了 NgForm
指令,以便何时可以获取它。我们还可以获得在 providers
数组中的 NgForm
指令上声明的任何标记。这条规则适用于任何节点。
另见
然后我将子 NgModel
指令手动添加到 NgForm
以便它们可以一起工作。
Angular有两种形式,Template Driven和Reactive。模板驱动表单无法实现您想做的事情,您需要查看 Reactive Forms
一般来说,它的工作原理是在组件中创建一个表单 object,然后在模板中使用它。 Angular 说这实际上更灵活,更容易测试,但我认为语法更难理解。
您需要在 parent 组件中使用:
myForm: FormGroup;
constructor(private fb: FormBuilder) { // <--- inject FormBuilder
this.createForm();
}
createForm() {
this.myForm = this.fb.group({
firstControl: '',
secondControl: '',
thirdControl: '',
fourthControl: ''
});
}
您的 parent 模板将如下所示:
<form [formGroup]="myForm" novalidate>
<input type="text"formControlName="firstControl" />
<input type="text" formControlName="secondControl" />
<child-component [parentFormGroup]="myForm">
</form>
并且您的 child 将接受表单组作为输入,模板将如下所示:
<div class="form-group" [formGroup]="parentFormGroup">
<input type="text" formControlName="thirdControl" />
<input type="text" formControlName="fourthControl" />
</div>