带有嵌套的 Angular 4 反应形式:在`setControl`

时间:2021-02-21 09:35:17

标签: angular-reactive-forms angular4-forms

我正在尝试提取 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 {
}
  • 第一次加载后,完整的表单可以正常工作(只有在所有字段都填写时,验证才会显示“true”)。
  • 按下 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 不支持嵌套表单控制结构;但是我在一些顶级字段上调用它(“私有”表单组,与嵌套的“共享”组无关)。

0 个答案:

没有答案