2

I'm trying to create a copy of my reactive form value object (with spread operator or Object.assign) and apply some changes to it before sending it to my server.

This is the code that builds up my form, and it works as expected in my template:

newTask: FormGroup

this.newTask = this.formBuilder.group({
      partner:              [null, [Validators.required]],
      title:                [null, [Validators.required, Validators.minLength(5), Validators.maxLength(50)]],
      description:          [null, [Validators.minLength(10), Validators.maxLength(120)]],
      responsible:          [null, [Validators.required]],
      type:                 [null, [Validators.required]],
      priority:             [null, [Validators.required]],
      status:               [null, [Validators.required]],
      history:              this.formBuilder.array([])
    })

The code below illustrates how I can add and remove elements from my history array:

createAction (action?) {
    return this.formBuilder.group({

      title: [action ? action.title : undefined, [Validators.required, Validators.minLength(5), Validators.maxLength(50)]],
      description: [action ? action.description : undefined, [Validators.required, Validators.minLength(10), Validators.maxLength(200)]],
      resolveAt: [action ? action.resolveAt : undefined],
      result: [action ? action.response : undefined, [Validators.minLength(10), Validators.maxLength(200)]],
      resolvedAt: [action ? action.resolvedAt : undefined],
      status: [action ? action.status : undefined, [Validators.required]],
      relatedPerson: [action ? action.relatedPerson : undefined]

    })
  }

  addAction (action?): void {
    const history = this.newTask.get('history') as FormArray
    history.push(this.createAction(action || initialActionState))
  }

  removeAction (i: number): void {
    const history = this.newTask.get('history') as FormArray
    history.removeAt(i)
  }

After the user input all needed data correctly, when I submit my form this is the modification that I have to perform:

let cleanVar = {...this.newTask.value}
// I could also use let cleanVar = Object.assing({}, this.newTask.value), the result is the same
    cleanVar.history.forEach(item => {
      item.status = item.status.string
      if (item.relatedPerson) item.relatedPerson = item.relatedPerson._id
    })
console.log(this.newTask.value)

As you can see I'm trying to modify the copy of the original object, but when I log this.newTask.value, the changes propagated to it too.

I've never had any problem like this before with object copies, so I'm trying to find out why is this happening. Maybe it's something related to Angular Reactive Forms that I'm not being able to detect.

Does someone know why is this happening?

Thanks!

Update

This is what is inside my newTask.value variable:

enter image description here

Felipe Micali
  • 827
  • 1
  • 11
  • 25
  • 2
    There is no copy. In this line `let cleanVar = {...this.newTask.value}` cleanVar becomes a reference to an object literal but that in turn has (references to) the 'original' elements from `newTask.value`. – marekful May 11 '18 at 11:53
  • Thanks for your answer. So how could I create a copy of my object? I thought the spread operator and Object.assign create copies without references... And in other cases I was able to achieve this, only when I try to copy the value of a reactive form this happens. – Felipe Micali May 11 '18 at 12:17
  • Can you share what's inside `newTask.value`? – marekful May 11 '18 at 12:21
  • Sure, it's in the updated version of my question. – Felipe Micali May 11 '18 at 12:30
  • 1
    If you have access to lodash library in your project, you can simply use `_.cloneDeep(objectToClone)` which will return you new copy. lodash.com/docs#cloneDeep – Rikin May 11 '18 at 12:52
  • Possible duplicate of [What's alternative to angular.copy in Angular](https://stackoverflow.com/questions/34688517/whats-alternative-to-angular-copy-in-angular) – Rikin May 11 '18 at 12:56
  • Cloning arrays in JS is tricky. If all elements are primitive values, you can achieve it with splice() but object elements will still be references then. Lodash is a good choice as it will take care of objects too. – marekful May 11 '18 at 13:02
  • Amazing, tried it and worked just fine! Thank you very much, everyone! – Felipe Micali May 11 '18 at 13:04

1 Answers1

0

As marekful and Rikin suggested, using lodash cloneDeep is the way to go:

import { cloneDeep } from 'lodash'

let clonedVar = cloneDeep (originalVar)

// do whatever you need with clonedVar and originalVar isn't touched

Thanks everyone!

Felipe Micali
  • 827
  • 1
  • 11
  • 25