There's a few things that I can see. For starters your first example has "map" defined as an array:
@track myMap = [];
Your second uses the JS Map object which will not map to anything in apex.
Apex Data structures
A customer can be represented as
Class
public class customer {
public String FirstName {get; set;}
public String LastName {get; set;}
}
Map
Map<String, Object> customer; // Notice that the second param is object, not string
// This allows for support of any data type as a value such as boolean or decimal
JS Maps
The JS Map object will not translate to any native objects in SF. I suppose in theory you could create a class in SF that might be able to work but thats much more work then necessary.
A map
in Apex more closely translates to an Object
in javascript. The Key in the map is the Name of the attribute in the Object and the value in the map is the value of the attribute. Lets use the below JS as an example:
// Map<String, Object> or a single Customer
var object = {'FirstName':'Bob','LastName':'smith'};
// Or List<Map<String, Object>> or List<Customer>
var objects = [
{'FirstName':'Bob','LastName':'smith'},
{'FirstName':'Fred','LastName':'Flintstone'}
];
// Or Map<String, Object> or Map<String, Customer>
var map = {
"003XXXXXXXXXXXX": {..Customer object}
"003XXXXXXXXXXXX": {..Customer object}
};
Passing data to apex
There are 2 ways to pass data like this to apex. First, is to pass it into an appropriately typed parameter
public static String getresults(Map<String, Object> customer)
public static String getresults(Customer customer)
// -- Or, for multiple customers --
public static String getresults(List<Map<String, Object>> customers)
public static String getresults(List<Customer> customers)
// -- Or for Map<Id, Customer>
public static String getResults(Map<String, Object> customers) {
for (String recordId : customers.keySet()) {
Map<String, Object> customer = (Map<String,Object>) customers.get(recordId);
system.debug(customer.get('FirstName));
}
}
public static String getResults(Map<String, Customer> customers) {
// This one requires customer to be a top level class I believe
// See my comments about stringifying below as it may work better
}
The second is to JSONify your data and pass it as a string
Javascript
var object = {'FirstName':'Bob','LastName':'smith'};
getResults(JSON.stringify(object));
Apex
public static String getresults(String customer) {
// Typecast yourself
Customer c = (Customer) JSON.deserialize(customer, Customer.class);
}
// Or
// For Map<Id, Customer>
public static String getResults(String customers) {
Map<Id, Customer> = (Map<Id, Customer>) json.deserialize(customers, Map<Id, Customer>.class);
}
With aura components I believe that the second option was a more reliable approach as the built in serialization/deserialization was known to cause issues with some data types, including custom classes (I believe a custom class needs to be a top level class to work as a parameter but with this approach it can be a second level class).
Conclusion and TL;DR
The most reliable approach is to always pass your data as a JSON string and handle the deserialization on the apex side yourself. This does require you to know how to properly deserialize json in Apex.
Additional notes
JSON based REST services operate the same way. See this answer which I think tries to convey the same information but in the context of JSON REST services.
This fails because the Model class is an inner class. It is probably a bug, but we hit this a while back and found:
- instances of inner classes can be returned to the client but cannot be passed to the server
- instances of top level classes can be passed both ways
As per sfdcfox's comment, we most often saw an internal server error when trying to pass an instance of an inner class to an aura enabled method.
The documentation does say:
Custom classes used for component attributes shouldn’t be inner classes or use inheritance. While these Apex language features might work in some situations, there are known issues, and their use is unsupported in all cases.
Whilst this appears to be for Aura code, the LWC documentation indicates LWC has the same behaviour (see the link for "Apex" in the section entitled "Expose Apex Methods to Lightning Web Components"). So whilst it is probably a bug, they have documented to say things can go wrong if you try to use inner classes.
Something else that can cause issues is the use of @AuraEnabled public attributes in your data object, which can be remedied by switching to public properties. This MAY allow you to keep the class as an inner class, but there's no guarantee this will work in all cases. Certainly changing your inner Model class to a top level one like the following will resolve any issues:
public class Model {
@AuraEnabled
public String someAttribute { get; set; }
}
Best Answer
Make members
public
and@auraEnabled
, then they will be available in the lightning component.