I'm trying to build a function that will produce a copy of a given FormGroup
. I started with:
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);
}
But that doesn't work if there is a FormArray
or FormGroup
. This one might work if it were recursive, but I couldn't get a good handle on it.
I also attempted to solve it with
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;
}
But that didn't work for double-nested FormGroups
, any FormArrays
or regular FormControls
...
I also tried:
function copyForm(form: FormGroup): FormGroup {
const copy = new FormGroup(Object.assign({}, form.value));
return copy;
}
But that gives me the error:
ERROR TypeError: control.setParent is not a function
I'm stumped.
This is the deep copy function I came up with which also retains the associated validator / async validator functions and disabled status of each 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;
}
If you have simple FormGroups that contain only FormControls (i.e. not FormGroups or FormArrays), and you know their structure in advance, then this is a simple solution:
Note: by using initaliseFormGroup
for initalising the original FormGroup, you will match the validators for each control.
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;
}
If you have more complex forms (with child FormGroups), or want to clone them dynamically without knowing their structure in advance, then the other answers will better suited.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With