function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
bretondevbretondev 

Loooking for Best Practice : Chaining two asynchronous Apex calls from a Lightning Component

In my company I was facing a scenario where I had to chain two Apex asynchronous calls:
First I needed to call myApexMethod1 which returns a result myResult
Secondly I needed to call myApexMethod2 but needed to provide myResult as a parameter to the method.


So this is the first version I coded :
 
({
    "myFunction" : function(cmp) {


        var action = cmp.get("c.myApexMethod1");
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
               myResult = response.getReturnValue();
            }
        });
        $A.enqueueAction(action);


        var action2 = cmp.get("c.myApexMethod2");
	action2.setParams({ myParam : myResult });
        action2.setCallback(this, function(response) {
            var state2 = response.getState();
            if (state2 === "SUCCESS") {
               //Do something
            }
        });
        $A.enqueueAction(action);


    }
})

This code compiles well but there is a problem:
Since the calls are asynchronous, by the time we reach :
action2.setParams({ myParam : myResult });

it is not guaranteed that myResult is filled, because at that time nothing guarantees that myApexMethod1 has executed since it is asynchronous.

To avoid this behaviour, I decided to nest the second call inside the callback of the first method.
That gives the following code :
 
({
    "myFunction" : function(cmp) {


        var action = cmp.get("c.myApexMethod1");
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {

               myResult = response.getReturnValue();

               var action2 = cmp.get("c.myApexMethod2");
	       action2.setParams({ myParam : myResult });
               action2.setCallback(this, function(response) {
                   var state2 = response.getState();
                   if (state2 === "SUCCESS") {
                        //Do something
                   }
               });
               $A.enqueueAction(action);

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

    }
})

I have tested it and it works.

But my question is:
Is it the proper way to chain these asynchronous calls?
Next time maybe I will have to chain a lot of asynchronous calls and this pattern does not look very clean?
Is there a better practice to chain these asynchronous calls?

 
Amit Singh 1Amit Singh 1
Yes, this is the only way to chain the request in Lightning Component. For better code practice you can write the separate method and then call form the callback method.
Paul McCollum 16Paul McCollum 16
Dealing with a similar challenge. Question: Shouldn't the nested "action2" be called in the $A.enqueueAction(action) function.
Shouldn't line #20 be $A.enqueueAction(action2); instead of $A.enqueueAction(action);  ?
bretondevbretondev
Yes you're right, there's a typo here, so correct code is :
 
({
    "myFunction" : function(cmp) {


        var action = cmp.get("c.myApexMethod1");
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {

               myResult = response.getReturnValue();

               var action2 = cmp.get("c.myApexMethod2");
	       action2.setParams({ myParam : myResult });
               action2.setCallback(this, function(response) {
                   var state2 = response.getState();
                   if (state2 === "SUCCESS") {
                        //Do something
                   }
               });
               $A.enqueueAction(action2);

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

    }
})

 
Paul McCollum 16Paul McCollum 16
<imho>
I'm no lightning expert but that matches the async js patterns i've seen in the wild. 
For cleanliness, i think you could have 2 functions and as long as you call function2 like you are doing in the Success processing block. 
At that point, it might be more proper to have the 2nd function set as a helper but i'm still figuring that controller/helper distinction out myself. 
</imho>
Donald DedmanDonald Dedman
Although there was a typo in action2 being called I really appreciated your response.I had the right idea, but was unsure on how to carry it out...Also, I did learn another way so the callouts are not nested...
action.setCallback (this, result => this.myCtrlMethod(component, result))