18

Is it possible to iterate over a Map in an aura:iteration. It doesn't give me a compile or runtime error but it doesn't appear to work.

My thought is that it works similarly to $.each in jquery.

<aura:attribute type="Map" name="myMap"  default="{key1: 'item1', key2: 'item2'}" />       
<aura:iteration items="{!myMap}" indexVar="key" var="item">
      {!key} : {!item} 
</aura:iteration>
4
  • What is actually in myMap? It's possible that default value may not be working.
    – Kris Gray
    Jun 5, 2015 at 17:11
  • Also pretty sure this would work over a list, but I don't think it works over maps.
    – Kris Gray
    Jun 5, 2015 at 17:12
  • I used default value just as a simple example but in my actual component it's a parameter being fetched from the server. It does work if I use a list instead and I could work around the issue by having a response object that contains the key and value in the object but it would just be a lot more elegant if I could use the map directly Jun 5, 2015 at 18:22
  • I have a solution for this. We could create a child component that will accept the map and its key. So based on key we will get the value
    – Ratan Paul
    May 24, 2016 at 13:45

5 Answers 5

11

According to the Aura docs it looks like this is only defined to iterate over a List.

If you have not seen the Aura docs app before it is available with any Salesforce instance by modifying the URL:

[your instance stuff].salesforce.com/auradocs/reference.app

Or to navigate to the page for the iteration component:

[your instance stuff].salesforce.com/auradocs/reference.app#reference?descriptor=aura:iteration&defType=component
6
  • 3
    You can also check out the source code for aura:iteration from the open source project, if you want to see how it works. It may not be exactly this in the Lightning implementation, but will give you an idea. github.com/forcedotcom/aura/blob/master/aura-components/src/…
    – pchittum
    Jun 6, 2015 at 22:05
  • Thanks! I was afraid of that. The lightning developer reference specifies that it iterates over a collection, which I believe is incorrect since maps and sets are collections developer.salesforce.com/docs/atlas.en-us.lightning.meta/… developer.salesforce.com/docs/atlas.en-us.lightning.meta/… Jun 7, 2015 at 17:32
  • 1
    That's a very good point, it is a little misleading. I jumped strait to the Type defs!
    – Kalin
    Jun 9, 2015 at 1:01
  • @scott morrison did you got the answer. I am also looking for map iteration in lightning. However I accomplished this by help of wrapper type list.
    – Ankuli
    Jun 13, 2015 at 19:39
  • So far the answer is that it is not supported and the docs are in error in stating that the iterator iterates over a collection, it only iterates over a list Jun 22, 2015 at 19:13
5

I came across this question and was a little discouraged, but looks like things might have changed since some of these answers were provided.

I found this page in the Lightning Components documentation. All the way at the bottom, and really easy to overlook is what appears to be instructions for iterating over an Apex Map returned from a server-side controller.

I tried it out and it actually works! This controller function populates a picklist <ui:inputSelect ... /> in a Lightning Component by iterating over an Apex Map.

I guess this doesn't exactly answer the original question, but maybe the workaround is to do the iteration in a controller function and provide those results to the view.

({
    doInit : function(component, event, helper) {
        // Create the action
        var action = component.get("c.getApexMap");
        // Add callback behavior for when response is received
        action.setCallback(this, function(response) {
            var state = response.getState();
            console.log(state);
            if (component.isValid() && state === "SUCCESS") {
                //loop through map returned from Server, populating client picklist as we go

                var clientMap = response.getReturnValue();     //the apex map returned from server
                var opt = new Array();                         //this will be our picklist options

                for(key in clientMap) {     //this iterates over the returned map
                    opt.push({ class: "optionClass", label: clientMap[key].labelField__c,
                                                     value: clientMap[key].valueField__c });
                }

                component.find("myPicklist").set("v.options", opt);
            } else {
                console.log("Failed with state: " + state);
            }
        });
        // Send action off to be executed
        $A.enqueueAction(action);
    }
})
3

Not a straight Yes to the original question. The Maps can not go in directly, but we can use some thing like this.

Maps or list, all the collections are same for lightning components as it considers all these variables as json.

Try the following: Component:

    <aura:component >

    <aura:attribute name="colercodes" type="list"/> 
    <ui:button press="{!c.getColCodes}" label="Display Colors" />
    <aura:iteration items="{!v.colercodes}" indexVar="key" var="col">
        <p>
            <aura:set attribute="style" value="{!col.BGvalue}"/>
            {!key}: {!col.key} - {!col.value}
        </p>
    </aura:iteration>

</aura:component>

ComponentController.js:

({
    getColCodes: function(component) {
        var cols = []; 
            cols.push({
                value: '#F0F8FF',
                BGvalue: 'background:#F0F8FF',
                key: 'AliceBlue'  
        });
            cols.push({
                value: '#00FFFF', 
                BGvalue: 'background:#00FFFF',
                key: 'Aqua'  
        });
            cols.push({
                value: '#FAEBD7',
                BGvalue: 'background:#FAEBD7',
                key: 'AntiqueWhite' 
        });
            cols.push({
                value: '#7FFFD4',
                BGvalue: 'background:#7FFFD4',
                key: 'Aquamarine'  
        });

        component.set("v.colercodes", cols);
    }
})

===================

I happened to use something like this in one of my projects:

({
    doInit : function(component, event, helper) {
        var action = component.get("c.returnArticles");//Fetching Map/queryresult from Controller
        action.setCallback(this, function(a) {
            component.set("v.ArticleMap", a.getReturnValue()); 
            var Arts = component.get("v.ArticleMap"); 
              console.log(Arts); 
            var artsTemp = [];
            for (Art in Arts){
                console.log(Art);
            var temp =  Arts[Art]
            for (keyofMap in temp){ 

                //pushing the articles into Map/ List of component attribute
                artsTemp.push({
                    key: keyofMap,
                    value: temp[keyofMap]
                });
            } 
            }
            component.set("v.ArticleList", artsTemp);

        });
        $A.enqueueAction(action);
    }
})

Note: I was returning database.query() from the apex controller there.

We can not directly use the maps like we do in VF pages, we can pass that maps to json variable as they are and use them in components.

HTH

3
  • It looks to me as though you are using an object array rather than a map no? For me a map is something that you can get a value of like this: objectName.keyName
    – swervo
    Mar 4, 2016 at 15:12
  • This is not a way to iterate a map but a list.
    – Leisure
    Jun 28, 2016 at 6:47
  • This works for me. Especially after spending considerable time searching for a workable example of iterating over a map (the recommended SF way).
    – Bryan
    Jun 9, 2018 at 18:08
0
  • Write a wrapper Class for your Map which consists on the map(consider 'myMap') and set of keys(conisder 'myKeys').
  • Create an attribute(Consider 'myWrapper') of the wrapper class.
  • In you can get all the keys by {!myWrapper.myKeys}.
  • In the controller, for getting the value of specific key, use

    var testMap = component.get('v.myWrapper');

    var value = testMap.myMap[key];

0

Like @Prabhan I found that using object array in the client side component was the only way to get iteration to work.
My question was "With Lightning Components how can you iterate over a client side list of objects or map?"

Maybe someone can improve on this or show a complete example in the docs. In my case I needed to display a list of properties from a Case record.

BetaCaseController

public with sharing class BetaCaseController {
    @AuraEnabled
    public static Case getCase(Id id) {
        Case aCase = [
            select Id, ParentId, CaseNumber, CreatedDate, Description, IsClosed, IsDeleted, Origin, OwnerId, Priority, Reason, Status, Subject, Type, ClosedDate, AccountId, ContactId
            from Case WHERE Id = :id
         ];
        // Perform isAccessible() check here 
        return aCase;
    }
}

BetaComponent

<aura:component controller="BetaCaseController"
    implements="flexipage:availableForRecordHome,force:hasRecordId"
    access="global">
    <aura:attribute name="theCase" type="Case" />
    <aura:attribute name="properties" type="list" />
    <aura:attribute name="recordId" type="String" />
    <aura:attribute name="message" type="String" default="empty" />
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    <div class="slds-form" role="list">
        <aura:iteration items="{!v.properties}" indexVar="key" var="prop">
            <div class="slds-grid slds-gutters_small">
                <div class="slds-col slds-has-flexi-truncate" role="listitem">
                    <div
                        class="slds-form-element slds-form-element_edit slds-hint-parent">
                        <div class="slds-form-element__label">{!prop.label}</div>
                        <div class="slds-form-element__control">{!prop.value}</div>
                    </div>
                </div>
            </div>
        </aura:iteration>
    </div>
    <div>T8</div>
</aura:component>

BetaComponentComponent.js

({
    doInit : function(component, event, helper) {
        var action = component.get("c.getCase");
        action.setParams({"id": component.get("v.recordId")});
        action.setCallback(this, function(response){
            var state = response.getState();
            component.set("v.message", state);
            if (state === "SUCCESS") {
                var theCase = response.getReturnValue();
                component.set("v.theCase", theCase);
                var properties =  [];
                properties.push({ 'label' : 'CaseNumber', 'value': theCase.CaseNumber});
                properties.push({ 'label' : 'Subject', 'value': theCase.Subject});
                properties.push({ 'label' : 'Status', 'value': theCase.Status});
                properties.push({ 'label' : 'Parent', 'value': theCase.Parent});
                properties.push({ 'label' : 'IsClosed', 'value': theCase.IsClosed});
                component.set("v.properties", properties);
            }
        });
        $A.enqueueAction(action);       
    },   
})

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.