Iterate Apex Maps in Lightning Web Component

Apex method returning map datatype as response cannot be directly iterated in HTML of Lightning Web Component. It becomes complex when we have list of maps or nested map structure. This article is going to help you to handle different kind of map structure within Lightning Web Component.

Let’s create a Lightning Web Component within your VS Code with name apexMap and an Apex controller named apexMapController.

apexMap.html

The html has 4 lightning-card, first card has 3 buttons to load different types of map using iteration and showing its internal structure. Second card shows you the simple map structure and its iteration using for-each iterator. Third lightning-card shows list of map structure and its iteration whereas fourth one shows nested map structure and its iteration.

<template>
    <lightning-card title="Iterate Apex Maps in LWC" icon-name="custom:custom63">
        <lightning-button label="Load Simple Map" onclick={handleLoadSimpleMap} slot="actions"></lightning-button>
        <lightning-button label="Load List of Maps" onclick={handleLoadListMap} slot="actions"></lightning-button>
        <lightning-button label="Load Map inside Map" onclick={handleNestedMap} slot="actions"></lightning-button>
    </lightning-card>
    <lightning-card if:true={showSimpleMapCard} title="Simple Map" icon-name="custom:custom63">
        <lightning-layout pull-to-boundary="medium">
            <lightning-layout-item flexibility="auto" padding="horizontal-medium">
                <template if:true={simpleMapStr}>
                    <div class="scroller">
                        <pre>{simpleMapStr}</pre>
                    </div>
                </template>
            </lightning-layout-item>
            <lightning-layout-item flexibility="auto" padding="horizontal-medium">
                <ul if:true={simpleMap} class="scroller">
                    <template for:each={simpleMap} for:item="map">
                        <li key={map.key}>{map.key} : {map.value}</li>
                    </template>
                </ul>
            </lightning-layout-item>
        </lightning-layout>
    </lightning-card>
    <lightning-card if:true={showListMapCard} title="List Map" icon-name="custom:custom63">
        <lightning-layout pull-to-boundary="medium">
            <lightning-layout-item flexibility="auto" padding="horizontal-medium">
                <template if:true={listOfMapStr}>
                    <div class="scroller">
                        <pre>{listOfMapStr}</pre>
                    </div>
                </template>
            </lightning-layout-item>
            <lightning-layout-item flexibility="auto" padding="horizontal-medium">
                <ul if:true={listOfMap} class="scroller">
                    <template for:each={listOfMap} for:item="map">
                        <li key={map.Id}>{map.key} : {map.value}</li>
                    </template>
                </ul>
            </lightning-layout-item>
        </lightning-layout>
    </lightning-card>
    <lightning-card if:true={showNestedMapCard} title="Nested Map" icon-name="custom:custom63">
        <lightning-layout pull-to-boundary="medium">
            <lightning-layout-item flexibility="auto" padding="horizontal-medium">
                <template if:true={nestedMapStr}>
                    <div class="scroller">
                        <pre>{nestedMapStr}</pre>
                    </div>
                </template>
            </lightning-layout-item>
            <lightning-layout-item flexibility="auto" padding="horizontal-medium">
                <ul if:true={nestedMap} class="scroller">
                    <template for:each={nestedMap} for:item="map">
                        <li key={map.key}>{map.key}</li>
                        <template for:each={map.value} for:item="innermap">
                            <li key={innermap.key}>{innermap.key} : {innermap.value}</li>
                        </template>
                    </template>
                </ul>
            </lightning-layout-item>
        </lightning-layout>
    </lightning-card>
</template>

apexMap.js

The javascript file of the lwc imports three apex method which returns three different types of map datatype. It has three onclick handler which calls the apex method and parse the map value in object array structure to iterate using for-each directive in HTML file.

import { LightningElement } from 'lwc';
import fetchSimpleMap from '@salesforce/apex/apexMapController.fetchSimpleMap';
import fetchListMap from '@salesforce/apex/apexMapController.fetchListMap';
import fetchNestedMap from '@salesforce/apex/apexMapController.fetchNestedMap';

export default class ApexMap extends LightningElement {
    simpleMapStr;
    listOfMapStr;
    nestedMapStr;
    simpleMap = [];
    listOfMap = [];
    nestedMap = [];
    showSimpleMapCard = false;
    showListMapCard = false;
    showNestedMapCard = false;

    handleLoadSimpleMap() {
        fetchSimpleMap().then((result) => {
            console.log('result', result);
            this.simpleMap = [];
            for (var key in result) {
                this.simpleMap.push({ key: key, value: result[key] });
                console.log('key', key, result[key]);
            }
            this.simpleMapStr = JSON.stringify(result, null, 2);
            this.showSimpleMapCard = true;
            this.showListMapCard = false;
            this.showNestedMapCard = false;
        }).catch((error) => {
            console.log(error);
        });
    }
    handleLoadListMap() {
        fetchListMap().then((result) => {
            console.log('result', result);
            this.listOfMap = [];
            let idCounter = 0;
            result.forEach(element => {
                for (var key in element) {
                    this.listOfMap.push({ key: key, value: element[key], Id: idCounter });
                    ++idCounter;
                    console.log('key', key, element[key]);
                }
            });
            this.listOfMapStr = JSON.stringify(result, null, 2);
            this.showSimpleMapCard = false;
            this.showListMapCard = true;
            this.showNestedMapCard = false;
        }).catch((error) => {
            console.log(error);
        });
    }
    handleNestedMap() {
        fetchNestedMap().then((result) => {
            this.nestedMap = [];
            console.log('result', result);
            for (var key in result) {
                let value = [];
                for (var innerkey in result[key]) {
                    value.push({ key: innerkey, value: result[key][innerkey] });
                }
                this.nestedMap.push({ key: key, value: value })
                console.log('key', key, result[key]);
            }
            this.nestedMapStr = JSON.stringify(result, null, 2);
            this.showSimpleMapCard = false;
            this.showListMapCard = false;
            this.showNestedMapCard = true;
        }).catch((error) => {
            console.log(error);
        });
    }
}

apexMap.css

.scroller {
    height: 300px;
    overflow: auto;
    padding: var(--lwc-varSpacingXSmall, 8px);
    border: solid var(--lwc-borderWidthThin, 1px) #eee;
}

apexMap.js-meta.xml

The xml defines the metadata of the Lightning Web Component. You can use this component with Home, Record and App Lightning pages.

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>55.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>

apexMapController.cls

The apex controller of the Lightning Web Component is very simple. It has three methods which is returning hard coded map values.

public with sharing class apexMapController {
    @AuraEnabled
    public static Map<String,String> fetchSimpleMap(){
        try {
            Map<String,String> simpleMap = new Map<String,String>();
            simpleMap.put('fruit','apple');
            simpleMap.put('vegetable','potato');
            return simpleMap;
        } catch (Exception e) {
            throw new AuraHandledException(e.getMessage());
        }
    }

    @AuraEnabled
    public static List<Map<String,String>> fetchListMap(){
        try { 
            List<Map<String,String>> lstofMap = new List<Map<String,String>>();
            Map<String,String> simpleMap1 = new Map<String,String>();
            simpleMap1.put('fruit','apple');
            simpleMap1.put('vegetable','potato');
            lstofMap.add(simpleMap1);
            Map<String,String> simpleMap2 = new Map<String,String>();
            simpleMap2.put('fruit','mango');
            simpleMap2.put('vegetable','Cabbage');
            lstofMap.add(simpleMap2);
            return lstofMap;
        } catch (Exception e) {
            throw new AuraHandledException(e.getMessage());
        }
    }

    @AuraEnabled
    public static Map<String,Map<String,String>> fetchNestedMap(){
        try { 
            Map<String,Map<String,String>> nestedMap = new Map<String,Map<String,String>>();
            Map<String,String> simpleMap1 = new Map<String,String>();
            simpleMap1.put('fruit','apple');
            simpleMap1.put('vegetable','potato');
            nestedMap.put('map1',simpleMap1);
            return nestedMap;
        } catch (Exception e) {
            throw new AuraHandledException(e.getMessage());
        }
    }
}

Demo – Apex Maps in LWC

Apex Maps in LWC

You can visit https://salesforcediaries.com/category/lightning-web-component/ to get more update on Lightning Web Component.

Leave a Reply