[SalesForce] How to send Javascript map as a parameter from lightning component to Apex server controller

I have a lightning component which enqueues server side action. To that action I need to pass a map as one of the parameters, but it looks like it takes memory address of the object instead.

The client side code that creates the map and calls the server side action:

var action = cmp.get("c.save");
var mapToSend = new Map()
for (var key of valueMap.keys()) {
    mapToSend.set(key, valueMap.get(key))
}
action.setParams({
    "name": cmp.get("v.name"),
    "params": mapToSend
});

In the controller then:

 public static Boolean save(String name, Map<String, Object> params) {

log of the javascript shows nice Map with all the correct fields, but salesforce system log shows just

14:55:16.0 (3172304)|VARIABLE_SCOPE_BEGIN|[41]|name|String|false|false
14:55:16.0 (3188041)|VARIABLE_ASSIGNMENT|[41]|name|"Account"
14:55:16.0 (3191758)|VARIABLE_SCOPE_BEGIN|[41]|params|Map<String,ANY>|true|false
14:55:16.0 (3204719)|VARIABLE_ASSIGNMENT|[41]|params|{}|0x30d2397a

Any Idea why? What those |false|false and |true|false mean in the logs?

Best Answer

Don't use Map, just use a normal Object. Here's a demonstration:

Apex:

public class LightningMap {
    @AuraEnabled public static void doMap(Map<String, Object> values) {
        System.debug(values);
    }
}

Lightning Controller:

({
    doInit: function(component, event, helper) {
        var action = component.get("c.doMap");
        action.setParams(
            {
                "values": {
                    "Hello": 5,
                    "World": 15
                }
            }
        );
        action.setCallback(this, function(result) {} );
        $A.enqueueAction(action);
    }
})

Demo App:

<aura:application controller="LightningMap">
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
</aura:application>

Logged output:

13:16:24.0 (1462121)|USER_DEBUG|[3]|DEBUG|{Hello=5, World=15}

For a more directly applicable version, this is probably what you want:

var mapToSend = {}
for (var key of valueMap.keys()) {
    mapToSend[key] = valueMap.get(key);
}
action.setParams({
    "name": cmp.get("v.name"),
    "params": mapToSend
});
Related Topic