5

I'm getting some strange results trying to do a simple demo of lightning:radioGroup using aura:if to conditionally render components. I've added a controller method to show the weirdness.

Component:

<aura:component implements="flexipage:availableForAllPageTypes">
    <aura:attribute name="opts" type="Map[]"
                    default="[
                             {'label': 'apples', 'value': 'a'},
                             {'label': 'oranges', 'value': 'o'}
                             ]"/>
    <aura:attribute name="value" type="String" default="o"/>
    <lightning:radioGroup type="button"
        aura:id="mygroup" onchange="{!c.myAction}"
        name="radioButtonGroup"
        label="Radio Button Group"
        options="{!v.opts}"
        value="{!v.value}"
        required="true" />
    <aura:if isTrue="{!v.value=='a'}">
        <p>Option 1 is selected (simple).</p>
    </aura:if>
    <aura:if isTrue="{!v.value=='o'}">
        <p>Option 2 is selected (simple).</p>
    </aura:if>
    <aura:if isTrue="{!(''+v.value)=='a'}">
        <p>Option 1 is selected (coerced).</p>
    </aura:if>
    <aura:if isTrue="{!(''+v.value)=='o'}">
        <p>Option 2 is selected (coerced).</p>
    </aura:if>
</aura:component>

Controller:

({
    myAction : function(c, event, helper) {
        var value = c.get('v.value');
        console.log(value);
        console.log(value+'');
        console.log(value == 'a');
    }
})

So basically, on initial load with a default value of "o", it starts on oranges (option 2) and I get both Option 2 paragraphs rendering. Once I flip the button, I only get the "coerced" Option 2 paragraphs.

When I monitor in the browser's Developer Console, I see:

Proxy { <target>: Array[1], <handler>: Object }
WARNING: Unsupported a method: Symbol(Symbol.toPrimitive). Returning undefined
a
WARNING: Unsupported a method: Symbol(Symbol.toPrimitive). Returning undefined
true

So even though the selected radio option maps to the simple string "a", the result retrieved from it is still a proxied object.

In the markup this has the totally unintuitive effect of failing to meet an equality test with the string "a" in an aura:if statement. However, if I coerce the value to a string in the expression syntax by adding it to an empty string, the equality test now works.

In the controller this seems to still produce normally expected results (the proxy object passes an equality test with "a") aside from the console.log result. However, it does throw that strange error message.

FWIW: I already tried initializing opts in the controller instead of the view and I get the same result.

Is this a new and odd behaviour? Bug-report-worthy?

3 Answers 3

6

The attribute value on the lightning:radioGroup is defined as an object.

https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/aura_compref_lightning_radioGroup.htm

But that's because it's defined on the generic lightning:inputable interface. The lightning:radioGroup component writes it as an array, and it gets lockerized.

Thanks to your detailed repro steps (really appreciated), I was able to validate the issue, and I have contacted the relevant team for clarification.

UPDATE: there is a known issue with the lightning:radioGroup value onChange handler: the value data type changes from String to Array.

2
  • Thanks JF. Let me know how this proceeds. It seems to me that the desired outcome should be for binding expressions to have intuitive results regardless of the involvement of Locker Service.
    – Charles T
    Oct 23, 2017 at 11:25
  • Is there a Link which we can follow on the Known Issues site?
    – VarunC
    Dec 21, 2017 at 13:50
1

I think this is right behavior from javascript point of view. When component fire onchange it returned value in proxied object and that is why your UI fails because it can't compare array with String but when you do "" + you are interally calling javascript datatype casting, to elaborate this more there are three approaches for converting to string in case if you don't know

  • value.toString()
  • "" + value (This is what you are following): The plus operator is fine for converting a value when it is surrounded by non-empty strings.
  • String(value): This approach is nicely explicit: Apply the function String() to value.

so to get result without "" in your UI, add following code in your controller

({
   myAction : function(c, event, helper) {
    var value = c.get('v.value');
    console.log(value);
    console.log(value+'');
    console.log(value == 'a');
    var changeValue = event.getParam("value"); //get updated value
    c.set('v.value',String(changeValue));  //assign back to value attribute as string
instead of object
  }
})
3
  • I can see why JavaScript causes this to happen, however, from the point of view of data binding it should not be necessary to implement a controller method to do type casting just so that the aura:ifcan evaluate intuitively.
    – Charles T
    Oct 23, 2017 at 11:22
  • @CharlesT yes I agree with you and as JF acknowledged this defect we should hear from him very soon :)
    – Himanshu
    Oct 23, 2017 at 11:50
  • 1
    the String(value) saved my day
    – SamuelDev
    Jan 23, 2018 at 8:12
0

Looks like Spring'18 has fixed the bug the value is a String not an Array anymore.
Which means the workaround is now a bug. Happy fixing everyone

1
  • Thanks for the pointer. I would think that, coercing it to a String for comparison should not cause anything to break once it returns an actual String.
    – Charles T
    Jan 9, 2018 at 12:43

You must log in to answer this question.

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