2/15/2017 Update
Per comment from Doug in one of the answers this is an issue with Locker service. I verified that with Locker disabled is works as expected...
In Spring 17 as of today, with locker enabled it is still not working however
Update
So, since we get an internal error when passing classes/objects to apex controllers AND if values are not set in the controller when the component requests them then there is no way to pass those properties back (see below), I am left with this mess for every non string property
@AuraEnabled public String endDate {
get {
return endDate == null ? '' : endDate;
}
set;
}
private date endDateValue {
get {
if (string.isBlank(endDate)) return null;
return date.valueOf(endDate);
}
set {
if (value == null) endDate = null; else endDate = string.valueOf(value);
}
}
Should not have to go through all that to use a simple class property in a component...Ugh
Original discussion
So I have been fighting with this for a while. Maybe my mindset is wrong and what I am doing is correct but it just seems like a lot of extra work.
Scenario
- Component with attribute set to a type of a custom class
- Input boud to a property in that class
Now is it too much to as that when the data is entered in the input that it is reflected in the component? The actual input keeps the value but the attribute is never set....
It makes it extremely difficult to pass data around. Right not I am manually setting the attribute properties based on the value input in the component.
So the examples:
The first input when data is input always logs as:
{}
The second input the data logs correctly when value are input into the field.
The weird part is that accessing the actual property outputs as expected:
console.log(component.get('v.myCustomClass.myTestString'));
outputs
a
as shown in the second debug line in the image
Custom Class
public class myProblemClass {
@AuraEnabled public string myTestString {get;set;}
public myProblemClass(){
}
public myProblemClass(String setDefault){
mytestString = setDefault;
}
}
Apex Controller
public class myProblemController {
@AuraEnabled
public static myProblemClass newProblemClass(){
return New myProblemClass();
}
@AuraEnabled
public static myProblemClass newProblemClassInitial(){
return New myProblemClass('initial');
}
}
Lightning Component
<aura:component description="myProblemComponent" controller="myProblemController">
<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
<aura:attribute name="myCustomClass" type="myProblemClass"/>
<aura:attribute name="myCustomClassInitial" type="myProblemClass"/>
<div class="slds-form-element">
<label class="slds-form-element__label" for="text-input-01">Input Label</label>
<div class="slds-form-element__control">
<ui:inputText aura:id="firstInput" updateOn="keyup" keyup="{!c.logMe}" requiredIndicatorClass="slds-required"
required="true" value="{!v.myCustomClass.myTestString}" placeholder="Enter Me"
class="slds-input"/>
</div>
</div>
<div class="slds-form-element">
<label class="slds-form-element__label" for="text-input-01">Input Label</label>
<div class="slds-form-element__control">
<ui:inputText updateOn="keyup" keyup="{!c.logMe}" requiredIndicatorClass="slds-required"
required="true" value="{!v.myCustomClassInitial.myTestString}" placeholder="Enter Me"
class="slds-input"/>
</div>
</div>
</aura:component>
Component Controller
({
doInit: function (component, event, helper) {
var action = component.get("c.newProblemClass");
var actionInitial = component.get("c.newProblemClassInitial");
action.setCallback(this, function (response){
component.set('v.myCustomClass',response.getReturnValue());
})
actionInitial.setCallback(this, function (response){
component.set('v.myCustomClassInitial',response.getReturnValue());
})
$A.enqueueAction(action);
$A.enqueueAction(actionInitial);
},
logMe: function(component,event,helper){
console.log(JSON.stringify(component.get('v.myCustomClass')));
console.log(component.get('v.myCustomClass.myTestString'));
console.log(JSON.stringify(component.get('v.myCustomClassInitial')));
}
})
Now, I get that in the first attribute that I am not setting the value of the class property thus the Java object does not contain anything. However, when I set a value in the first Input that is Bound to the class property I would expect it to set it.
The questions:
- Are my expectations incorrect
If #1 is true then is setting the value of the attribute as follows the correct way. Keeping in mind my real class has 20-30 properties so that is a lot of extra code to write just to set the values
component.get('v.myCustomClass').myTestString = component.find('firstInput').get('v'value');
So as Ashwani points out, the binding of the value on the input get set properly so you can access the property directly. So why does it still output as {}
when logging the attribute.
Now if I do this:
component.get('v.myCustomClass').myTestString = 'ABCDEF';
console.log(JSON.stringify(component.get('v.myCustomClass')));
then JSON of the attribute outputs the correct JSON string (see 4th debug line). So I can set it in the JS but there is no way to set it in using the actual Input field?? But you can access the property directly when set by the input field v.myCustomClass.mytestString
....Confusing.....
console.log(JSON.stringify(component.get('v.myCustomClassInitial')));
is working fine for me