3

I'm working on making my lightning components compliant with Locker Service, and I see something strange happens with javascript variables after calling component.set() on them.

A component is having an attribute:

<aura:component controller="CPQ_QOT02_ConfigurationLC" access="GLOBAL">
    ...
   <aura:attribute name="item" type="Object" access="GLOBAL"/>
    ...
</aura:component>

In the init method of controller I'm calling server to fetch item variable. Item is a complex JS object having several properties (maps and arrays). Response from server is ok, I'm handling it in helper in below lines:

line   code

126    if (response.status == "SUCCESS") {
127        var item = JSON.parse(response.data);
128        console.log(item);
129        component.set("v.item", item);
130        console.log(component.get("v.item"));
131        ...

There is a significant difference between console.log that is printed to console in line 128 (before calling set) and in line 130 after calling it.

Here are snapshots from the browser console:

Console.log from line 128:

console.log from 128

Console.log from line 130 (after setter was called. Looks like all properties are not directly visible):

console.log from 130

As a result - whatever I would do later with the "v.item" variable - it seems not being applied to that attribute. Before locker service, everything was working fine, but also the result of both console.log's were the same.

Am I doing something wrong, or this is some framework issue?

  • did you find any solution for this issue? I activated the locker service today, and ohh boy, some weird stuff are happening! Thanks – RareFever Jul 27 '17 at 11:59
3

This is definitely supposed to be a "feature" of Locker Service... an object stored in the framework becomes a "SecureObject" instead. Presumably this is designed to enable data binding to the view. But it is not documented particularly well.

Some things I have found:

  • Data binding to a JS object works slightly better if you declare the aura:attribute as a Map not an Object.
  • When you first component.set the Map it should contain all the keys it will ever have, otherwise newly added properties may not bind properly.
  • If you pass an object to another component and it tries to modify it and then bind to its own view, you may end up with trouble. Sometimes I find myself cloning objects passed from other components (i.e. using something as silly as JSON.parse(JSON.serialize(obj))).
  • Thank you for answer @Charles, so as I understand the only option to pass an object to another component and modify it there is this JSON.parse... If that's the case - I'm in a big trouble. – Maciek Simm Jun 30 '16 at 15:28
  • I really am not sure how it works, I just know that when a JS object is set from one component and bound to another component which then tries to modify it, there is some trouble. I would like to hear more on this from the SF team. – Charles T Jun 30 '16 at 15:47
  • Yes, yes, yes. If I could give you several upvotes, I would. I've spent the last week or so figuring out these kinds of things - they are not specified anywhere else!! – Caspar Harmer Jun 30 '16 at 22:32
  • A useful detail is that if you want to set the variable's default value to an empty object, you can use default="{}" but only if you've set the type to Map. If you set type to Object it will parse it as a string literal "{}". I should also add, if a variable will contain an array of JS Objects, then you can declare it as type Map[] for best results. – Charles T Jul 2 '16 at 5:39
  • So summarizing, I can see that primitive types seem to be passed properly between parent & child components. Complex types not. If I remeber correctly, that's the other way around compared to Visualforce Components. – Maciek Simm Jul 4 '16 at 13:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.