Get variable access scope which is set from result of an imperative apex call in another block

javascriptlightning-web-componentsmapvariable-scope

I have a method in which I am making an imperative apex call which returns the result in the form of a Map<String, Boolean>, this again I am converting to a map (I need it in map form as in iteration below I will use map.get) in the client side since the map is coming as an object from Server side. Problem is when I'm converting the map within this block it shows in the console, but when I am accessing this map in an iteration in another block below (in the same method) it is undefined as per console log, so my logic is failing. Here is the code

import getFavAccountBoolean from '@salesforce/apex/ECX_AccountPickerHelper.getFavAccountBoolean';
import { LightningElement, wire, track } from 'lwc';
import { loadStyle } from "lightning/platformResourceLoader";
import { NavigationMixin } from 'lightning/navigation';

 export default class EcxAccountPicker extends NavigationMixin(LightningElement) {

    mapNew ;


// other code

 objectToMap(obj){

        return new Map(Object.entries(obj));
    }


  convertToObject(returnValue){
        let arr=[];
        var map1 = new Map();
            
        this.accountSet = returnValue;
        console.log('all accounts are', this.accountSet);

        getFavAccountBoolean({emaAccounts: this.accountSet}).then(result =>{

         map1 = this.objectToMap(result);

        console.log('map is' ,map1);  // this console showing correct output as expected
       
        }).catch(error =>{

            console.log(error);

        })  
    
        this.mapNew = new Map(map1);
        console.log('checking if map value copied', this.mapNew);  // shows undefined

        this.accountSet.forEach((item,index) =>{
            if(item != null){
                let obj ={};
                obj.id = item.TargetId;
                obj.accountName = item.Target.Name;
                obj.address = item.Target.ShippingCity + ', '+ item.Target.ShippingState;
                obj.accountNumber = item.Target.EC_Account_Number__c;
                obj.tag = item.Target.EC_Division__c;
              
       console.log('map is', map1);   // undefined
       console.log('fav value for this particular account', map1.get(item.TargetId))  //undefined
                obj.isFav = map1.get(item.TargetId); // undefined
                
       }     

The Apex method works fine as I checked applying debug logs,it returns an object of account Id and boolean value. I initially was using let map1 = new Map() then I realized the difference between let and var so I used var for function scope as well, problem is outside the block of imperative server call wherever I am accessing the map value it shows undefined. I even tried setting it at a global LWC class level variable as above still it shows undefined. What can be the possible reason that I am not able to access this map1 outside the imperative apex call block?

Best Answer

An imperative Apex call runs asynchronously. Consider the following code:

function doAsync() {
  return new Promise((resolve) => setTimeout(resolve,100));
}
console.log('I am first');
doAsync().then(() => console.log('I am third'));
console.log('I am second');

You'll see the following output:

I am first
I am second
(( note: 1/10th of a second delay here ))
I am third

The reason why you don't see any output here:

console.log("checking if map value copied", this.mapNew); // shows undefined

Is the same reason why I am second came before I am third; the asynchronous code has not had a chance to run yet. Either place all of your logic into the .then callback, or use async and await:

  // async is required to use await in a function
  async convertToObject(returnValue) {
    let arr = [];
    var map1 = new Map();

    this.accountSet = returnValue;
    console.log("all accounts are", this.accountSet);

    // Your code will pause here until the results are available
    let result = await getFavAccountBoolean({ emaAccounts: this.accountSet })
    map1 = this.objectToMap(result);

    console.log("map is", map1); // this console showing correct output as expected

    this.mapNew = new Map(map1);
    console.log("checking if map value copied", this.mapNew); // shows undefined

    this.accountSet.forEach((item, index) => {
      if (item != null) {
        let obj = {};
        obj.id = item.TargetId;
        obj.accountName = item.Target.Name;
        obj.address =
          item.Target.ShippingCity + ", " + item.Target.ShippingState;
        obj.accountNumber = item.Target.EC_Account_Number__c;
        obj.tag = item.Target.EC_Division__c;

        console.log("map is", map1); // undefined
        console.log(
          "fav value for this particular account",
          map1.get(item.TargetId)
        ); //undefined
        obj.isFav = map1.get(item.TargetId); // undefined
      }
    });
  }