我正在尝试提取 Angular 4 反应式表单的一部分(一个表单组),以便在多个父表单中重用它。 “重新组装”的表单工作正常,但是当我通过组件的逻辑更新 父 表单的一部分(不是子表单!)时,它的控件绑定以某种方式中断:setControl()
。 >
这是一个最小的例子(与实际情况相比,我在从远程 API 接收数据后调用 setControl
- 在 ngOnInit
等完成后):
src/index.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>ng4-min</title>
<base href="/">
</head>
<body>
<root></root>
</body>
</html>
src/root.component.html
<form [formGroup]="rootForm">
<div formGroupName="private">
<label for="a">a</label>
<input type="text" id="a" name="a" formControlName="a"/>
<label for="b">b</label>
<input type="text" id="b" name="b" formControlName="b"/>
</div>
<shared [parentForm]="rootForm"></shared>
<button (click)="setControl()">setControl</button>
<span>{{rootForm.valid}}</span>
</form>
src/root.component.ts
import {Component, OnInit} from "@angular/core";
import {FormBuilder, FormGroup, Validators} from "@angular/forms";
@Component({
selector: 'root',
templateUrl: './root.component.html',
})
export class RootComponent implements OnInit {
public rootForm: FormGroup;
constructor(private formBuilder: FormBuilder) {
}
ngOnInit() {
this.rootForm = this.formBuilder.group({
private: this.formBuilder.group({
a: ['', <any>Validators.required],
b: ['', <any>Validators.required],
}),
shared: this.formBuilder.group({
c: ['', <any>Validators.required],
d: ['', <any>Validators.required],
})
});
}
setControl() {
this.rootForm.setControl("private", this.formBuilder.group({
a: ['A', <any>Validators.required],
b: ['B', <any>Validators.required],
}));
}
}
src/shared.component.html
<ng-container [formGroup]="parentForm">
<div formGroupName="shared">
<label for="c">c</label>
<input type="text" id="c" name="c" formControlName="c"/>
<label for="d">d</label>
<input type="text" id="d" name="d" formControlName="d"/>
</div>
</ng-container>
src/shared.component.ts
import {Component, Input} from "@angular/core";
import {FormGroup} from "@angular/forms";
@Component({
selector: 'shared',
templateUrl: './shared.component.html'
})
export class SharedComponent {
@Input()
parentForm: FormGroup;
}
package.json
{
"name": "ng4-min",
"version": "0.0.1",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build"
},
"private": true,
"dependencies": {
"@angular/compiler": "^4.2.2",
"@angular/common": "^4.2.2",
"@angular/core": "^4.2.2",
"@angular/forms": "^4.2.2",
"@angular/platform-browser": "^4.2.2",
"@angular/platform-browser-dynamic": "^4.2.2"
},
"devDependencies": {
"@angular/cli": "1.2.6",
"@angular/compiler-cli": "^4.2.2",
"ts-node": "~2.0.0",
"tslint": "~4.5.0",
"typescript": "~2.2.0",
"enhanced-resolve": "3.3.0"
}
}
src/app.module.ts
import {BrowserModule} from "@angular/platform-browser";
import {NgModule} from "@angular/core";
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import {RootComponent} from "./root.component";
import {SharedComponent} from "./shared.component";
@NgModule({
declarations: [
RootComponent,
SharedComponent
],
imports: [
BrowserModule,
FormsModule, ReactiveFormsModule
],
bootstrap: [RootComponent]
})
export class AppModule {
}
setControl
后,“a”和“b”字段值在 UI 中不会改变;然而,底层控件似乎接收到这些值(例如,即使我只填写“c”和“d”,验证也会显示“true”)。<shared>
标记(以及 RootComponent
代码中的“c”、“d”控件)并重复上述步骤,则表单在 setControl
(值在代码中设置,实际出现在表单字段中)。我做错了什么,我该如何解决/解决它?升级 Angular 不是 ATM 的选项。
在示例中,我可以将 setControl
替换为表单控件路径遍历(以定位每个组件),后跟 setValue
;
this.rootForm.controls["private"].get("a").setValue('A');
this.rootForm.controls["private"].get("b").setValue('B');
但如果我真的想在某个时候替换整个表单组怎么办?为什么外化子表单组的存在会破坏父上的setControl
?
This SO answer from "Using setControl in nested reactive form" 提到 setControl
不支持嵌套表单控制结构;但是我在一些顶级字段上调用它(“私有”表单组,与嵌套的“共享”组无关)。