There are four different things that work different and should not be mixed up:
- Attributes visible to Apex (
System.debug(object)
)
- Attributes visible to JSON.serialize
- Attributes visible to Aura
- Attributes visible to VisualForce
At the end of this post, you will find the class with different types of attributes (public; getter; getMethod; auraEnabled; transient). But first I want to point out the differences between these four possible outputs.
1) Apex Debug: Only declared attributes are printed. getAttribute methods aren't visible if we debug the object itself, not even {get{return x;}} is executed (null). They only get executed, when we access them directly.
Thing:[auraEnable=x, getter=null, publc=x, transi=x]
2) JSON: JSON.serialize uses the same information, so it only sees declared attributes, but also knows how to call their getters get{return x;}
, so we are one step further. (You can use transient
to hide it from JSON).
{"publc":"x","getter":"x","auraEnable":"x"}
3) Aura: Aura sees everything, that is @auraEnabled and knows how to call the getters to get its information. It is not using JSON.serialize()!
Object { method: "x", auraEnable: "x", getter: "x" }
4) Visualforce: sees all attributes including transient and (oddly) also auraEnabled (but doesn't know how to execute getters without direct calls.) In fact VF sees everything that is also outputted in debug(thing);
Thing:[auraEnable=x, getter=null, publc=x, transi=x]
The Answer:
Aura seems to be the smartest of all these possibilities to output an object. It is the only one that executed both getter methods. JSON.serialize only executed the public get{}.
So in your case, I would suggest replacing your interface with an abstract class using the template method pattern:
public abstract class theInterface{
public String className { public get{ return getClassName(); } set; }
public abstract String getClassName();
}
public class ImplementingThing extends theInterface{
@auraEnabled
public override String getClassName() {
return ImplementingThing.class.getName();
}
}
This would work in Aura and in your Test. Be aware that there are some issues about abstract classes and their properties in Lightning. Here are some more ways to get the classes name.
This is the code to verify all this:
public class ObjectCtrl {
@auraEnabled
public static Thing getThing() {
Thing result = new Thing();
System.debug(result);
System.debug(JSON.serialize(result));
return result;
}
public class Thing {
public String publc = 'x';
@auraEnabled
public String getter { public get{ return 'x'; } set; }
@auraEnabled
public String getMethod() {
return 'x';
}
@auraEnabled
public String auraEnable = 'x';
transient
public String transi = 'x';
}
}
Visual Force:
<apex:page controller="ObjectCtrl">
{!thing}
</apex:page>
Lightning App (Aura):
<aura:application controller="ObjectCtrl">
<aura:handler name="init" value="{!this}" action="{!c.onInit}"/>
</aura:application>
({
onInit: function(cmp, evt, helper) {
var action = cmp.get("c.getThing");
action.setCallback(this, function(response) {
console.log(response.getReturnValue());
});
$A.enqueueAction(action);
},
})
Your code is using string values as if they were actual Boolean primitives:
appEvent.setParams({"showRenderB" : "True" ,
"showRenderA" : "False"});
Because in JavaScript a non-empty String value is truthy, this results in your
<aura:renderIf isTrue="{!v.renderA}">
evaluating to true
: the string "False" is true, in this context. (Yes, it's very confusing to practitioners of strongly-typed languages!)
Fix: use actual primitive Boolean values:
appEvent.setParams({"showRenderB" : true,
"showRenderA" : false});
Best Answer
The role attribute is only documented for Lightning Web Components (LWC)
In Aura, Design Attribute Considerations and Aura Component Bundle Design Resources mentions the only attributes Flow Builder supports:
As such, you won't be able to do designate it as inputOnly in Aura. You'd have to convert your Aura component into a Lightning Web Component.