Angular Reactive Form - Form Array - 如何使用扩展运算符设置 FormArray?

分享于2023年03月15日 angular angular-reactive-forms formarray typescript 问答
【问题标题】:Angular Reactive Form - Form Array - How do I set FormArray with spread operator?Angular Reactive Form - Form Array - 如何使用扩展运算符设置 FormArray?
【发布时间】:2023-03-14 14:03:01
【问题描述】:

我有一个formarray。如果我使用表单构建器对其进行初始化并推动它,它似乎可以正常工作。如果我采用与从中推送项目相同的数组,并尝试使用展开运算符一次将其全部添加,我会收到错误“错误错误:找不到路径的控件:'sizesArray -> 0'”

我的问题是,按照 ngrx/rsjx/功能响应式编程的精神,我怎样才能保持 Formarray '不可变'并从 FormGroup[] 分配给它,而不是清除、循环和推送?

以下是相关代码:

sizesArray: FormArray;
sizesArray2: FormArray;
sizes: Observable;

constructor(
    private productStore: Store,
    private fb: FormBuilder
  ) {
    this.sizes = productStore.select(productState.selectSizes);
  }

ngOnInit() {


    this.sizesArray = this.fb.array([]);
    this.sizesArray2 = this.fb.array([]);

    this.sizes
      .pipe(
        skipWhile(sizes => !sizes),
        map(sizes => {
         return sizes.map(size => this.fb.group({size}));
        }
       )
      )
      .subscribe(
        sizes => {
          // this is the code I want to use.  that throws the error
          this.sizesArray = this.fb.array([...sizes]);

          // this code works, but I don't know how it's different than the code above
          this.sizesArray2.clear();
          sizes.forEach( size => {
            this.sizesArray2.push(size);
          });

        }
      );

    this.sizeForm = this.fb.group({
      sizesArray: this.sizesArray
    });

  }

还有我的模板:

...
Sizes
...

谢谢!

  • 你不能对像 formGroup 这样复杂的对象使用扩展运算符,(扩展运算符给出“属性”的副本而不是方法,是的,你有,例如“属性”setValue,但不是一个“方法” setValue)。注意:我认为如果你使用 this.fb.array(sizes) 它必须是工作
  • @eliseo - 好点。我打算引入 lodash 的 cloneDeep 来解决它。谢谢!

【解决方案1】:

我认为问题在于您正在 更改 引用

this.sizeForm = this.fb.group({
  sizesArray: this.sizesArray
});

此时 sizeArray 指向 this.sizesArray 引用的值,即 this.fb.array([]) 。然后,在订阅者的下一个回调中,您将更改引用。这个值也被 formControlName='sizesArray' “捕获”,这意味着

将创建多个 FormGroup 实例,它们是容器 sizesArray 的子级,该容器为空。

现在, this.sizesArray (您在模板中对其进行迭代)指向其他内容,即: this.fb.array([...sizes])

所以,基本上发生的事情是 sizesArray sizeForm 的孩子)指向一个空的 FormArray ,而 this.sizesArray 指向一个 非空 FormArray

在这种情况下你可以这样做:

.subscribe(sizes => {
  this.sizeForm.setControl('sizeArray', this.fb.array(sizes))
})

【讨论】:

  • 就是这样。谢谢!我想我认为表单将引用我的 this.sizesArray 变量,而不是该变量的值,所以当我更改它时,我认为表单将继续指向变量并且变量将指向新位置。错误的。我最终将下面的代码: this.sizeForm = this.fb.group({ sizesArray: this.sizesArray }); 移动到一个函数并在 this.fb.array([...sizes]) 之后再次调用它,效果非常好。
  • 很高兴它成功了! Here's 一篇深入探讨 Angular 表单的文章,如果您想了解更多关于它们的有趣信息!
  • 从那以后我对此做了更多的研究,我猜想来自 C# 背景的事实是,在 javascript 和 typescript 中,对象是通过引用传递的,但是对对象的引用是传递的按价值得到我。这真的很违反直觉,我仍然在思考它。这个问题的答案也给了我一些真正的见解: stackoverflow.com/questions/518000/…
  • 感谢分享! but references to objects are passed by value 我不确定这是不是真的。他们在我看来, sizesArray 指向 [] 。而 [] sizeForm 使用。然后 sizesArray 指向另一个数组 [...sizes] ,所以初始的 [] 不可能被更新。