代码之家  ›  专栏  ›  技术社区  ›  vince

角反应形式的深度复制?

  •  10
  • vince  · 技术社区  · 6 年前

    我正在尝试构建一个函数,该函数将生成给定 FormGroup . 我从以下内容开始:

    function copyForm(form: FormGroup): FormGroup {
      const copy = new FormGroup({});
      for (let key of Object.keys(form.value)) {
        const control = form.controls[key];
    
        /* Copy the data from the control into a new control */
        const copyControl = new FormControl({[key]: control.value});
    
        copy.addControl(key, copyControl);
     }
    

    但如果有 FormArray FormGroup格式组 . 如果它是递归的,这个可能会工作 ,但我无法很好地处理它。

    我还试图用

    function copyForm(form: FormGroup): FormGroup {
      const copy = new FormGroup({});
      for (let key of Object.keys(form.value)) {
        const control = form.controls[key];
        const copyControl = new FormControl({...control.value});
        copy.addControl(key, copyControl);
      }
      return copy;
    

    }

    但这对双重嵌套不起作用 FormGroups 任何 FormArrays 或常规 FormControls ...

    我还尝试了:

    function copyForm(form: FormGroup): FormGroup {
      const copy = new FormGroup(Object.assign({}, form.value));
      return copy;
    }
    

    但这给了我一个错误:

    ERROR TypeError: control.setParent is not a function
    

    我被难住了。

    4 回复  |  直到 6 年前
        1
  •  32
  •   John    5 年前

    这是我提出的深度复制函数,它还保留了相关的验证器/异步验证器函数和每个AbstractControl的禁用状态。

    /**
     * Deep clones the given AbstractControl, preserving values, validators, async validators, and disabled status.
     * @param control AbstractControl
     * @returns AbstractControl
     */
    export function cloneAbstractControl<T extends AbstractControl>(control: T): T {
      let newControl: T;
    
      if (control instanceof FormGroup) {
        const formGroup = new FormGroup({}, control.validator, control.asyncValidator);
        const controls = control.controls;
    
        Object.keys(controls).forEach(key => {
          formGroup.addControl(key, cloneAbstractControl(controls[key]));
        })
    
        newControl = formGroup as any;
      }
      else if (control instanceof FormArray) {
        const formArray = new FormArray([], control.validator, control.asyncValidator);
    
        control.controls.forEach(formControl => formArray.push(cloneAbstractControl(formControl)))
    
        newControl = formArray as any;
      }
      else if (control instanceof FormControl) {
        newControl = new FormControl(control.value, control.validator, control.asyncValidator) as any;
      }
      else {
        throw new Error('Error: unexpected control value');
      }
    
      if (control.disabled) newControl.disable({emitEvent: false});
    
      return newControl;
    }
    
        2
  •  11
  •   Nadhir Falta    5 年前

    我个人使用的lodash cloneDeep()函数如下:

    https://lodash.com/docs/#cloneDeep

    我这样使用它:

    const newFormGroup: any = _.cloneDeep(myFormGroup);

    如果需要强类型,可以添加 as FormGroup 正如@Andre Elrico在评论中所建议的:

    const newFormGroup = _.cloneDeep(myFormGroup) as FormGroup;

        3
  •  10
  •   displayName    4 年前

    我会这样做:

    copyFormControl(control: AbstractControl) {
        if (control instanceof FormControl) {
            return new FormControl(control.value);
        } else if (control instanceof FormGroup) {
            const copy = new FormGroup({});
            Object.keys(control.controls).forEach(key => {
                copy.addControl(key, copyFormControl(control.controls[key]));
            });
            return copy;
        } else if (control instanceof FormArray) {
            const copy = new FormArray([]);
            control.controls.forEach(control => {
                copy.push(copyFormControl(control));
            })
            return copy;
        }
    }
    
        4
  •  8
  •   Richard Dunn    4 年前

    如果您有简单的表单组 仅包含FormControls (即不是FormGroups或formarray),并且您事先知道它们的结构,那么这是一个简单的解决方案:

    注:通过使用 initaliseFormGroup 为了初始化原始FormGroup,您将匹配每个控件的验证器。

    initaliseFormGroup(){
        return new FormGroup({
            x : new FormControl('', Validators.required),
            y : new FormControl('', Validators.minLength(10))
        });
    }
    
    cloneFormGroup(oldForm: FormGroup){
        let newForm = this.initaliseFormGroup()
        newForm.patchValue(oldForm.value);
        return newForm;
    }
    

    如果您有更复杂的表单(带有子表单组),或者希望在不事先知道其结构的情况下动态克隆它们,那么其他答案将更适合。