【问题标题】:How to patch form value to a recursive nested Angular Form?如何将表单值修补到递归嵌套的 Angular 表单?
【发布时间】:2020-10-05 10:36:07
【问题描述】:

最近,我在 StackOverflow 上提出了以下问题,并收到了惊人的回复,结果是构建了一个递归嵌套的 Angular 表单:Angular Deeply Nested Reactive Form: Cannot find control with path on nested FormArrayHere is a blog post作者写的关于同一个问题

这种递归嵌套的 Angular 表单让我可以继续构建组 FormArrays,所有这些组都有一个 group 对象:

{
  "conjunctor": null,
    "conditions": [
      {
        "variable":   
      }
  "groups": []
}

您可以添加多个conditions 实例并进一步嵌套groups,如this StackBlitz 所示

从本质上讲,Form 组件已被拆分为多个组件: group-controlcondition-formaction-buttons-bar(发出动作的按钮)。这种方法可以满足我的所有需求,但是,我在通过这种递归方法修补表单值时遇到了麻烦。

到目前为止,我已经尝试发送一个静态语句对象并将其修补到整个表单本身,以及专门针对 groups 对象。这是它在

中的样子

应用组件:

(我也在group-control 组件中尝试了相同和相似的方法)。最终我计划使用来自 API 的数据来填充和修补这些值,但现在和测试,使用这些静态数据

  ngOnInit() {
    const data = {
      statement: {
        groups: [
          {
            conjunctor: "and",
            conditions: [
              {
                variable: "asdf"
              }
            ],
            groups: []
          }
        ]
      }
    };
    this._form.patchValue(data);
    console.log(this._form.value);
  }

是否可以在递归表单上修补 statement FormGroup 的表单值?

【问题讨论】:

    标签: javascript angular


    【解决方案1】:

    Stackblitz demo

    您的数据没有问题。这很可能是时间问题。在您可以修补任何值之前,表单必须是稳定的。当您在OnInit 中执行此操作时,我想您正在构造函数中构建表单。如果是这样,则该表单尚未准备好接收任何值。

    解决这个问题的最简单方法是使用不舒服的setTimeout。但我想这只是为了测试。在实际情况下,数据可能需要一段时间才能获得。

    如果你用前面提到的setTimeout 包装它,上面的例子就可以工作:

    ngOnInit() {
      setTimeout(() => {
        const data = {
          statement: {
            groups: [
              {
                conjunctor: "and",
                conditions: [
                  {
                    variable: "asdf"
                  }
                ],
                groups: []
              }
            ]
          }
        };
        this._form.patchValue(data);
        console.log(this._form.value);
      }, 50);
    }
    

    下面的动画 gif 显示了 3 个嵌套组中的补丁,最后一个嵌套在第二个组上。

    根据给定数据构建表单

    您可以做的一件有趣的事情是根据您拥有的数据自动构建表单。您可以通过分析进入ControlValueAccessor.writeValue 的数据来实现这一点:

    if (!value) {
      return;
    }
    setTimeout(() => {
      if (value && value.conditions && value.conditions.length) {
        this._conditionsFormArray.clear();
        value.conditions.forEach(c => this._addCondition());
      }
    
      if (value && value.groups && value.groups.length) {
        this._groupsFormArray.clear();
        value.groups.forEach(g => this._addGroup());
      }
    
      this._form.patchValue(value);
    }, 50);
    

    也许你已经注意到上面的setTimeout,因为我们在表单创建方法(在OnInit上调用)中有另一个setTimeout,它在表单创建后向表单添加条件,并创建条件本身就在setTimeout 中。因此,我们必须等待它运行,否则 this._conditionsFormArray.clear(); 不会有任何效果 => 运行时不会创建任何条件。

    private _createFormGroup() {
      this._form = this._fb.group({
        conjunctor: null,
        conditions: this._fb.array([]),
        groups: this._fb.array([])
      });
    
      // add one condition on the next tick, after the form creation
      setTimeout(() => this._addCondition());
    }
    

    然后通过一些调整,我们可以得到如下结果(下面的gif是基于这个另一个Stackblitz demo):

    【讨论】:

    • 这很好用,但是嵌套项呢?如果传入带有嵌套组的对象,则第二组似乎没有修补值
    • 它也有效。为了测试它,在 stackblitz 中,我增加了 5 秒的延迟,以便让我有时间在第 1 组中创建两个嵌套组,并在第二个嵌套组中创建更多嵌套组。我会在我的答案上放一个 gif 来表明这一点。
    • 谢谢。根据补丁添加组似乎是不可能的,对吧?就像修补这些数据,然后相应地显示 UI。它不会点击 addGroup 按钮,而是会得到响应(来自data obj),然后显示在 UI 上
    • 让我看看我是否遵循它:你想打补丁并根据数据动态创建相应的表单,对吗?
    • 这很棒。我注意到添加组按钮不再添加条件,所以在组控制writeValue 我将.length 添加到 setTimeout 内的 if 语句中
    猜你喜欢
    • 2021-12-02
    • 2021-03-25
    • 1970-01-01
    • 2017-11-03
    • 2020-08-06
    • 2021-02-20
    • 1970-01-01
    • 1970-01-01
    • 2020-04-04
    相关资源
    最近更新 更多