0

I have a particularly strange issue where one, and only one parameter to an Aura Action is undefined. Worse, it seems to be nondeterministic when it is undefined, and when it actually works. Relevant snippets for this Action (variable and file names obfuscated for anonymity):

Markup.cmp

<aura:attribute name="imTheProblem" type="Boolean" default="true"/>
<!-- ... -->
<lightning:input
    type="checkbox"
    label="I am the problem"
    name="imTheProblemCheckbox"
    checked="{!v.imTheProblem}"/>

Controller.js (not really relevant, but for thoroughness)

saveButtonPress : function(cmp, event, helper) {
    if (helper.fieldsValid(cmp)) {
        helper.save(cmp);
    }
},

Helper.js

save : function(cmp) {
    let action = cmp.get("c.save");
    console.log(">> problem attribute (on component) = " + cmp.get("v.imTheProblem"));
    console.log(">> problem parameter (in params) = " + action.getParam("imTheProblem"));
    action.setParams({
        "cont" : cmp.get("v.contact"),
        "cas" : cmp.get("v.case"),
        "notes1" : cmp.get("v.notes1"),
        "notes2" : cmp.get("v.notes2"),
        "dateString" : date,
        "number1" : cmp.get("v.number1"),
        "picklist1" : cmp.get("v.picklist1"),
        "picklist2" : cmp.get("v.picklist2"),
        "recordOwner" : cmp.get("v.recordOwner"),
        "text" : cmp.get("v.text"),
        "bool1" : cmp.get("v.bool1"),
        "string1" : cmp.get("v.string1"),
        "string2" : cmp.get("v.string2"),
        "sobj" : cmp.get("v.sobj"),
        "time1" : time1,
        "time2" : time2,
        "number2" : cmp.get("v.number2"),
        "number3" : cmp.get("v.number3"),
        "onsite" : cmp.get("v.onsite"),
        "bool2" : cmp.get("v.bool2"),
        "bool3" : cmp.get("v.bool3"),
        "bool4" : cmp.get("v.bool4"),
        "bool5" : cmp.get("v.bool5"),
        "bool6" : cmp.get("v.bool6"),
        "imTheProblem" : cmp.get("v.imTheProblem"),
    });

    console.log(">> problem attribute (on component) = " + cmp.get("v.imTheProblem"));
    console.log(">> problem parameter (in params) = " + action.getParam("imTheProblem"));

    action.setCallback(this, function(response) {
        if (response.getState() === "SUCCESS") {
            if (response.getReturnValue() === true) {
                this.sToast("Save completed successfully");
                this.refresh();
            }
        } else {
            for (var i = 0; i < response.getError().length; i++)
                this.eToast(response.getError()[i].message);
        }
    });
    $A.enqueueAction(action);
},

ApexController.cls

@AuraEnabled
public static Boolean apexMethod(Contact cont, Case cas, String notes1, 
    String notes2, String dateString, Decimal number1, String picklist1,  String picklist2, 
    String recordOwner, String text, Boolean bool1, String string1, String string2, 
    SObject sobj, String time1, String time2, Decimal number2, Decimal number3,
    Boolean bool2, Boolean bool3, Boolean bool4, Boolean bool5, Boolean bool6, Boolean imTheProblem) 
{
    // Does stuff
    return true;
}

The core issue is that sometimes, the save method in Apex is being called with imTheProblem set to null, instead of the parameter that is given. Since this is a boolean, this then blocks updates since a boolean should either be true or false, never null. The key is sometimes. For example, deploying code, refreshing the app and then running it once may work (but not always). I am running out of possible explanations for this seemingly nondeterministic behavior.

Things I have looked at:

  • Is the boolean in the component properly set?
    • Yes it is. JS console logs before and after the action params are set show it properly set in both cases.
  • Are there just too many parameters in the action?
    • No, completely removing one does not help at all. Same seemingly nondeterministic behavior.
  • Are there too many parameters in the action, and changing the order may help this one, and shift the problem elsewhere?
    • No, not only do I recall parameter order should match between the action and method being invoked, but changing it anyways makes no difference. The other parameters still work as expected, this one still doesn't.
  • Is this like passing a Date in to Apex from an action, where you have to construct the Date in the method body, or else it behaves like a string and causes a snowball of issues?
    • No, the boolean isn't being passed in as a string that needs to be reconstructed into an object. It is just plain null.

The only concrete thing I know is that the times that it is failing and calling the method with imTheProblem set to null, is that the parameters of the action aren't taking the assignment in setParams. From my browser's debug console (the first two lines are from before setParams is called, the second two lines are from after):

>> problem attribute (on component) = true
>> problem parameter (in params) = undefined
>> problem attribute (on component) = true
>> problem parameter (in params) = undefined

I am running out of ideas as to why, whether this be some limitation with the Aura framework, JavaScript voodoo, user error, I am unsure and would appreciate any other ideas and theories.

  • Do you have a "save" function in your helper and a "save" method in your Apex code? "Use unique names for client-side and server-side actions in a component. A JavaScript function (client-side action) with the same name as an Apex method (server-side action ) can lead to hard-to-debug issues." – George S. Aug 13 '19 at 17:08
0
  1. Firstly, there are too many parameters which may not hamper the functionality but definitely affects the readability and arises confusion.

  2. Booleans have such inconsistent behaviour when passed directly.

  3. The solution below is highly scalable and dynamic.

  4. Most importantly reusable and you will not get nulls instead of true/false.

  5. Also, the order does not really matter - which removes most of the confusion.

You can implement something like below:

Apex:

@AuraEnabled
public static Map<String, Object> fetchDataMap(Map<String, Object> params) {

    String objectName = params.containsKey('objectName') ? (String)params.get('objectName') : null;
    String fields = params.containsKey('fields') ? (String)params.get('fields') : null;
    String queryFilters = params.containsKey('queryFilters') ? (String)params.get('queryFilters') : null;
    String sortBy = params.containsKey('sortBy') ? (String)params.get('sortBy') : null;
    String queryType = params.containsKey('queryType') ? (String)params.get('queryType') : null;
    String soslSearchTerm = params.containsKey('soslSearchTerm') ? (String)params.get('soslSearchTerm') : null;
    Boolean sortAsc = params.containsKey('sortAsc') ? (Boolean)params.get('sortAsc') : false;
    Integer limitRecords = params.containsKey('limitRecords') ? Integer.valueOf(params.get('limitRecords')) : null;

In comp JS:

const params = {
            objectName: this.objectName,
            fields: this.fields,
            sortBy: this.sortBy,
            sortAsc: this.sortAsc,
            queryFilters: this.queryFilters,
            limitRecords: this.limit,
            queryType: this.queryType,
            soslSearchTerm: this.soslSearchTerm
        };
action.setParams({ params });

Also,

save : function(cmp) {
    let action = cmp.get("c.save");

Both JS function name and apex method name should not be same. It will go into recursion.

  • I am trying this solution but, funny enough, the whole "it works once and then starts being null every time" pattern continues with the Map. Except the Map isn't working either; calls to get() are returning another Map instance, and then the type casts fail in spectacular fashion. But after the initial run where it does this, the map is just plain null. I am starting to wonder if there is a greater problem and this is just one symptom... Side note, yes, the names should not be the same but for the sake of anonymizing I just renamed them both that way. In actual code, they are unique. – A stacked cube Aug 14 '19 at 15:29

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.