【问题标题】:How to update FormArray value with variable length如何使用可变长度更新 FormArray 值
【发布时间】:2019-10-17 23:05:25
【问题描述】:

如果我尝试在 FormArray 为空时设置 FormArray 值:

const array1 = new FormArray([]);
array1.setValue(['']);

我收到此错误:

还没有向该数组注册的表单控件。如果您使用的是 ngModel,您可能需要检查下一个刻度

如果我在有 1 的时候加 2:

const array2 = new FormArray([new FormControl('')]);
array2.setValue(['', '']);

我收到以下错误:

在索引 1 处找不到表单控件

如果我尝试在有 2 时设置 1:

const array3 = new FormArray([new FormControl(''), new FormControl('')]);
array3.setValue(['']);

我收到以下错误:

必须在索引处为表单控件提供一个值:1。

问题:如何编写一个函数来更新具有任意长度列表的表单数组的值?

StackBlitzhttps://stackblitz.com/edit/angular-wduzv9?file=src/app/app.component.ts

*编辑 我知道我可以使用push()at()removeAt(0) 方法。我正在寻找一个通用功能。它可以使用任何你想要的方法。

【问题讨论】:

  • 你为什么要这样做?
  • @Chellappan 在一种情况下,我将值与另一个控件同步。另一方面,有条件地插入默认值,然后在 FormControl 级别进行更新。不过这有关系吗?
  • FormArray 是基于索引的,您应该使用 at 方法访问,例如 array2.at(0).setValue(['']);
  • @Chellappan 是的,我完全理解并理解这一事实。你有答案吗?
  • 试试这个array2.reset(['','''])

标签: angular typescript angular-reactive-forms


【解决方案1】:

简化你的功能

getFormArray<T>(elements: T[]): FormArray {
    return new FormArray(
      elements.map((x: T) => {
        const obj = new FormGroup({});
        Object.keys(x).forEach(k => {
          obj.addControl(k, new FormControl(x[k]));
        });
        return obj;
      })
    );
  }

//the use, e.g.

this.formArray = this.getFormArray<any>([
  { id: 1, name: "Bob" },
  { id: 2, name: "Peter" }
]);

stackblitz

【讨论】:

  • 我想就地编辑 FormArray。但是,如果您没有这个要求,那就太好了。
【解决方案2】:

问题在于,如果不知道您希望在新索引处的 FormArray 中使用哪种类型的 AbstractControl,则无法在新键或索引处添加新值。

任何解决方案都必须考虑该索引应该是FormControlFormGroup 还是FormArray,因此我在setFormArrayValue 函数中提供了toSubControl 参数。 (我还提供了一些示例值来提供给这个参数。)

我选择删除所有项目,然后为每个值添加新控件。试图保留已有的控件会产生一些奇怪的行为。

这是我想出的解决方案:

type ControlFactory<T> = (values: T) => AbstractControl;

export function setFormArrayValue<T>(
    array: FormArray,
    values: T[],
    toSubControl: ControlFactory<T> = toFormControl
) {
    while (array.length) {
        array.removeAt(0);
    }
    values
        .map(toSubControl)
        .forEach(function(control) {
            array.push(control);
        });
    return array;
}

其中以下函数可以创建新的子AbstractControls。

// When the child controls should be FormControl
function toFormControl<T>(value: T) {
    return new FormControl(value)
}

// When the child controls should be FormGroup
function toFormGroup<T>(item: T) {
    const fields = Object.entries(item).reduce(function(hash, [key, value]) {
        hash[key] = new FormControl(value);
        return hash;
    }, {});
    return new FormGroup(fields);
}

// When the child controls should be FormArray of FormControls
function toFormArray<T>(values: T) {
    const fields = values.map(value => new FormControl(value));
    return new FormGroup(fields);
}

【讨论】:

  • 我在新的答案中改进(我希望)你的功能
【解决方案3】:

你可以初始化一个空的formArray,然后添加控件,然后设置值,


const arr = new FormArray([]);

const a = new FormControl('a', []);
const b = new FormControl('b', []);
const c = new FormControl('c', []);

arr.push(a);
arr.push(b);
arr.push(c);

console.log(arr.value);   // ["a", "b", "c"] 
// arr.setValue([0]);

console.log(arr) 
arr.controls[0].setValue('xxx')

console.log(arr.value);   // "xxx", "b", "c"

【讨论】:

  • 我如何使用这个函数来解决我的应用程序中的问题?
猜你喜欢
  • 1970-01-01
  • 2019-02-23
  • 2017-06-30
  • 1970-01-01
  • 2017-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-14
相关资源
最近更新 更多