15

I'm calculating a value while I pass it to a component. But for some reason this makes it immutable, so I can't update it in my component. These are some cases I played with:

<aura:application extends="force:slds">
    <aura:attribute name="value" type="Integer" default="{!1+1}" />

    <c:test value="2" />           //changeable
    <c:test value="{!2}" />        //changeable
    <c:test value="{#2}" />        //changeable
    <c:test value="{!1+1}" />      //immutable
    <c:test value="{#1+1}" />      //immutable
    <c:test value="{!v.value}" />  //immutable (same here, should be bound, but not final)
    <c:test value="{#v.value}" />  //changeable
</aura:application>

So I don't understand why 4-6 are immutable, there is nothing documented about this! I guess the last try is my way to go, but this is not how I expected it to work, maybe someone can bring some light into this.

Feel free to play around yourself:

c:test

<aura:component >
    <aura:attribute name="value" type="Integer" />

    <lightning:button label="Change Value to 10" onclick="{! c.changeValue }" />
    {!v.value}
</aura:component>

controller:

({
    changeValue: function(cmp, evt, helper) {
        cmp.set("v.value", 10);
    },
})
3
  • 6
    This looks like bug, but since it's not documented, I'm not sure anyone outside of one of the internal Lightning developers could say more. – sfdcfox Mar 20 '18 at 15:38
  • I didn't even know the # statement. What is it supposed to do? – Martin Lezer Mar 20 '18 at 17:47
  • 1
    # is a by-value expression. Instead of maintaining a reference, it'll be the raw result of whatever was passed in. – Kris Gray Mar 20 '18 at 18:26
7

This was intentionally designed this way, and reason for that is an edge case.

You can still change the value, you simply need to clear the reference before setting it first.

({
    changeValue: function(cmp, evt, helper) {
        cmp.clearReference("v.value");
        cmp.set("v.value", 10);
    },
})

Lets tell a little bit of a story here to explain whats going on.

kris:base

<aura:component extensible="true">
 <aura:attribute name="className" type="String" default="padding-bottom"/>
</aura:component>

kris:concrete

<aura:component extends="kris:base">
   <aura:set attribute="className" value="{!'padding-top ' + v.className}">
</aura:component>

As you can see, I'm setting an extended attribute via aura:set. It references back to the attribute you're already setting.

The expectation is clear to the developer, he wanted to take what the base class specified, and add a bit of additional information.

If he comes along later and does

({
   changeClassName: function(cmp) {
       cmp.set("v.className", "margin-top");
   }
})

Possible values of v.className now

  • "margin-top padding-bottom"
  • "margin-top"

In some situations you may want one value, and in some you'll want the other. What we decided at the time is that we won't make a choice. You'll need to clear the reference yourself, and decide what should happen.

We were recently revisiting this so its possible it'll change again, this merely explains the reasoning and current state of functionality.

Suggestions welcome.

8
  • I haven't seen cmp.clearReference() before is that part of the open api? – Caspar Harmer Mar 20 '18 at 20:30
  • 1
    Thanks for your detailed response! Clearing the reference only fixed it for line 6, but 4 and 5 are still immutable. My suggestion to your internal decision would be, that if someone overrides the old value, it's definitely his fault or even his/her intention, I would override it by design. It's a public value, so we need to treat it properly and be aware of this behaviour (as lightning does it with add/removeClass). – Basti Mar 20 '18 at 21:07
  • Yes, clearReference() is platform api exposed auraframework.org/auradocs#reference?topic=api:Component – Kris Gray Mar 20 '18 at 21:13
  • 1
    What do you mean? The code to test it is above and I tested it as described. – Basti Mar 21 '18 at 7:15
  • 1
    Well I'll be a monkeys uncle. We don't clear for computed references, only for references. ({!v.foo} is a reference, {!1+1} is a computed reference). Following up with the architect of the project to see whats the proper solution. – Kris Gray Mar 23 '18 at 0:51

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.