4

I have a lightning component that has 2 attributes and in input.

<aura:attribute name="wrapperObj" type="Object" />
<aura:attribute name="originalWrapperObj" type="Object" />

<input id="myField" onchange="{!c:doValidateChange}" type="text" />

Here is the Javascript controller

doValidateChange: function(cmp, event, helper) {
    helper.validateChange(cmp, event, helper);
},

Here is the Helper

validateChange: function(cmp, event, helper) {
    var val = event.currentTarget.value;
    cmp.set("v.wrapperObj.field1",val);
},

Here is what populates the attributes when the page loads

runWhenPageLoadsHlpr : function(cmp, event, helper) {
    var pageLoadAction = cmp.get("c.runWhenPageLoadsApx");
    pageLoadAction.setParams({
        "isCommunityBuilder" : isCommunityBuilder,
        "country" : country
    });
    pageLoadAction.setCallback(this, function(response){
         cmp.set("v.wrapperObj",response.getReturnValue());
         cmp.set("v.originalWrapperObj",response.getReturnValue());
    });
    $A.enqueueAction(pageLoadAction);
},

The problem is that when I change the field wrapperObj.field1 is getting populated with the value just like I would expect, but originalWrapperObj.field1 is also getting populated with the new value. I need it to maintain the original value. I am not updating originalWrapperObj.field1 so why would it update with the new value?

3
  • I guess you need to change {!c:doValidateChange} with {!c.doValidateChange} Commented Sep 26, 2018 at 19:02
  • So in JavaScript objects are assigned by reference that's why it's causing issue. To fix this cmp.set("v.wrapperObj", response.getReturnValue()); cmp.set("v.originalWrapperObj", Object.assign({}, response.getReturnValue())); try it in this way. Commented Sep 26, 2018 at 19:05
  • for deep clone you could use JSON.parse(JSON.stringify(response.getReturnValue())) Commented Sep 27, 2018 at 12:18

1 Answer 1

4

This is the nature of object oriented programming. An object holds a collection of values. However, the variable itself simply holds a reference to the object. This means that when you reuse the same object, you're reusing the same reference, which gives the appearance of the object being in two places at once.

As a simple example, consider this code:

var a = { value: 5 }
var b = a;
b.value = 10;
console.log(a.value); // outputs 10

To resolve this, you need to clone the object, which we would do like this:

var returnValue = response.getReturnValue();
var returnValueClone = Object.assign({}, returnValue);
cmp.set("v.wrapperObj",returnValue);
cmp.set("v.originalWrapperObj",returnValueClone);

Note that if you need a deep clone, you'd have to jump through more hoops, like outlined in this answer.

For an array of objects as a return value, you could use map/assign together:

var returnValueClone = returnValue.map(function(item) { return Object.assign({}, item)});
2
  • I tried using ` var returnValue = response.getReturnValue(); var returnValueClone = Object.assign({}, returnValue); cmp.set("v.wrapperObj",returnValue); cmp.set("v.originalWrapperObj",returnValueClone); ` but still have the same issue. The response back will be a wrapper class. ` public class responseWrapper { @AuraEnabled public User userObj {get;set;} @AuraEnabled public Contact candidate {get;set;} } `
    – Travis
    Commented Sep 26, 2018 at 20:11
  • @Travis In that case, you would need to clone two levels deep, as I tried to imply. You need to clone the objects so you have separate references.
    – sfdcfox
    Commented Sep 26, 2018 at 20:21

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .