Async enqueuing causing no return value

lightning-aura-components

I have a simple Aura comp. where I am trying to open custom object record creation page. Here, I am trying to pre-populate some of the fields on this creation form as I can access parent Case id from Pagereference as below:

CMP.js

var hotelId = helper.getHotelIdValue(component, caseId);
//other fields directly from Pagereference.
.
.
workspaceAPI.getEnclosingTabId().then(function(parentTabId) {
    //OpenSubtab with defaultFieldValues : component.find("pageRefUtils").encodeDefaultFieldValues(prepopulationValues)
}).catch(function(error) {
        console.log("error "+error);
});

HELPER.js

getHotelIdValue: function(component, caseId){
    var action = component.get("c.getHotelIdMethod");
    var hotelId;
    action.setParams({ caseId : caseId });
    action.setCallback(this, function(response) {
        var state = response.getState();
        if (state === "SUCCESS") {
            console.log('Return value: ' +response.getReturnValue());
            hotelId= response.getReturnValue();
        } else if (state === "ERROR") {
            var errors = response.getError();
            if (errors) {
                console.log(errors[0].message);
            } else {
                console.log("Unknown error");
            }
        }
    });
    $A.enqueueAction(action);
}

The problem here is – $A.enqueueAction(action); will place the server-side callback in the queue while my doInit gets executed on load. Due to this, my variable with CMP.js file var hotelId is getting as undefined as there won't be any value on initialization. I know the issue as stated in this SF documentation

$A.enqueueAction(action) adds the server-side controller action to the queue of actions to be executed. All actions that are enqueued will run at the end of the event loop. Rather than sending a separate request for each individual action, the framework processes the event chain and batches the actions in the queue into one request. The actions are asynchronous and have callbacks.

What is the workaround? How can I get the value of any field within my doInit function to pass it along to my subtab?

Best Answer

Convert your helper method to a Promise:

getHotelIdValue: function(component, caseId){
    return new Promise((resolve, reject) => {
        var action = component.get("c.getHotelIdMethod");
        var hotelId;
        action.setParams({ caseId : caseId });
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                console.log('Return value: ' +response.getReturnValue());
                hotelId = response.getReturnValue();
                resolve(hotelId);
            } else if (state === "ERROR") {
                var errors = response.getError();
                if (errors) {
                    console.log(errors[0].message);
                } else {
                    console.log("Unknown error");
                }
                reject(errors);
            }
        });
        $A.enqueueAction(action);
    })
}

Then use that to perform more async work, something like this:

helper
  .getHotelIdValue(component, caseId)
  .then((hotelId) => {
    workspaceAPI.getEnclosingTabId().then(function (parentTabId) {
      //OpenSubtab with defaultFieldValues : component.find("pageRefUtils").encodeDefaultFieldValues(prepopulationValues)
    });
  })
  .catch(function (error) {
    console.log("error " + error);
  });