如何使用 angular8 将对象数组绑定到 formGroup 和 formarray

Bhr*_*jni 5 angular angular-reactive-forms

您好,我使用反应式表单将对象数组绑定到 formArray,但在这里,如果我选择一个部分中的任何一项,然后单击“向右移动/向左移动”,则整个对象已从一个部分移动到另一部分。但该功能工作正常,但我无法检测到 form.valuechanges() 中从一个部分到其他部分所做的更改。任何人都可以帮助我检测更改,以防项目已从一个部分移动到另一部分,在这里我想要更改检测,但功能必须按原样工作,我的意思是整个对象从一个部分移动到另一部分。

提前致谢。

我这里有工作 demo2,我希望我之前发布的 demo1 能够像这个 demo2 一样工作,并且 formarray 工作。 演示2

演示: 演示 1

TS:

 private settingsGroupInfoForm() {
    if (!this.agentDetailsList) {
      // Add
     this.agentGroupViewInfoForm = this.FB.group({
          agentGroupView: this.FB.array(
            this.agentInView.map(x=>(x))
          ),
        })
    } else {
      // Edit
      if (this.agentDetailsList) {

       this.agentGroupViewInfoForm = this.FB.group({
          agentGroupView: this.FB.array(this.agentInView.map(x=>(x))),

      })
      }
      this.agentGroupViewInfoForm.valueChanges.subscribe(data => {
          this.formEdit = true;
          console.log('agentGroupViewInfoForm', this.formEdit)
        })
      }
    }
Run Code Online (Sandbox Code Playgroud)

HTML:

 <div class="card-body overflow-auto py-0" *ngIf="agentGroupViewInfoForm"
            [formGroup]="agentGroupViewInfoForm">
                <ul class="list-group list-group-flush" *ngFor="let child of agentInView"   name="agentInGroup" formArrayName="agentGroupView">
                  <li class="list-group-item {{isInActiveItems(child) ? 'active' : ''}}" (click)="toggleActiveItem(child)">
                    {{child.value}}
                  </li>
                </ul>
              </div>
Run Code Online (Sandbox Code Playgroud)

Kur*_*ton 8

你的问题

  • 您有 2 个相同类型的项目数组
  • 您想要为每个数组渲染一个表单数组
  • 您希望能够在数组之间移动项目
  • 您希望能够将表单值绑定回提交时的项目

该设计

与 Angular 中几乎所有基于组件的问题一样,您应该首先考虑模型。你的模型是王道,其他一切都是围绕它构建的。

在您的演示中,您正在列表之间移动项目。您正在更新模型并将 HTML 绑定到该模型。没有什么问题——这是正确的方法并且有效。

这里的额外挑战是您还想移动组。我们仍然需要考虑模型优先,但也要考虑在列表之间移动项目的同时移动相关状态。

简而言之,您目前拥有

list1: [];
selected1: [];

list2: [];
selected2: [];
Run Code Online (Sandbox Code Playgroud)

如果您想将项目从 1 -> 2 移动,您的移动方法将从items1到 中删除所有选定的项目items2。简单的。

添加表单后,您将拥有如下结构:

list1: [];
selected1: [];
form1: FormGroup;
formArray1: FormArray;

list2: [];
selected2: [];
form2: FormGroup;
formArray2: FormArray;
Run Code Online (Sandbox Code Playgroud)

当您将项目从 1 -> 2 移动时,您将继续将项目从 移动list1list2,但现在您还需要从 中删除相关项目formArray1并将其添加到formArray2

我存储了对表单数组的引用,以便以后更容易使用它们。

构建表单

使用表单数组可以说是这个答案中最复杂的部分。表单数组的关键是 HTML 结构模仿FormGroup您构建的对象的结构。

我们可以使用FormBuilder数组构建表单并绑定到它,如下所示:

组件.ts

buildForm() {
  this.model = [ 
    { value: 'a' }, { value: 'b' }, { value: 'c' }
  ];

  // create a form group for each item in the model
  const formGroups = this.model.map(x => this.formBuilder.group({
    value: this.formBuilder.control(x.value)
  }));

  // create a form array for the groups
  const formArray = this.formBuilder.array(formGroups);

  // create the top-level form
  this.form = this.formBuilder.group({
    array: formArray
  });
}
Run Code Online (Sandbox Code Playgroud)

并像这样在 HTML 中绑定它:

<form [formGroup]="form1" (submit)="onSubmit()">
  <div formArrayName="array">
    <div *ngFor="let item of list1; let i = index" [formGroupName]="i">
      <input formControlName="value" />
    </div>
  </div>
  <button>Submit</button>
</form>
Run Code Online (Sandbox Code Playgroud)

这将为数组中的每个项目生成一个输入,分别包含值“a”、“b”、“c”。

移动物品

在数组之间移动项目是一个简单的 JavaScript 问题。我们需要splice源数组和push目标数组。

要将项目从列表 1 移动到列表 2:

// move selected items from model 1
this.selected1.forEach(item => {
  const index = this.list1.indexOf(item);
  this.list1.splice(index, 1);
  this.list2.push(item);
});

this.selected1.length = 0;
Run Code Online (Sandbox Code Playgroud)

这将循环遍历列表 1 中的每个选定项,将其从列表中拼接出来,然后将其推送到列表 2。然后它会清除选定的项;

移动表单组

您将在移动项目的同时移动表单组。它在概念上是相似的——从一个中删除并添加到另一个中。您根据模型构建了表单数组,因此您知道索引匹配。

// move selected items from model 1
this.selected1.forEach(item => {
  const index = this.list1.indexOf(item);
  const formGroup: FormGroup = this.formArray1.controls[index] as FormGroup;

  this.list1.splice(index, 1);

  // move between form arrays
  this.formArray1.removeAt(index);
  this.formArray2.push(formGroup);

  this.list2.push(item);
});
Run Code Online (Sandbox Code Playgroud)

请注意此处有 2 条线用于在表单数组之间移动,它们看起来与用于在常规数组之间移动的 2 条线类似。

formArray.removeAt(index)formArray.push(formGroup)正在搬家。与表单数组的区别在于,我们需要首先使用 来获取对它的引用this.formArray1.controls[index] as FormGroup;

演示: https: //stackblitz.com/edit/angular-3cwnsv

警告

在此设计中,从数组和表单中删除以及添加到数组和表单的顺序很重要。您将 HTML 绑定到数组和表单。您通过循环数组来创建输入数组,并将每个项目绑定到i表单数组中的第 th 组。如果您先从表单中删除,则现在n数组中将包含项目,n - 1表单数组中将包含项目。尝试绑定到未定义的n表单组时,您将遇到错误。

您现在正在执行包含多个操作的事务。

除了确保按正确的顺序删除和添加之外,解决此问题的一种方法是使用OnPush更改检测。请仔细阅读本文,因为对于除最简单的应用程序之外的所有应用程序来说,这都是一个很好的策略。

下一步

为了回答的目的,我让我的演示保持简单。它的可扩展性或可重用性并不特别好。有很多重复的代码和错误的命名,试图避免被与应用程序相关的嵌套组件和属性名称分散注意力。

实际上,您可能想要创建一个子组件来负责我复制的许多代码。其设计绝对超出了这个问题的范围。

  • 必须说这是一个高质量的答案。 (2认同)