2

There's a Lightning Component with a button. Its onClick attribute points to a client-side controller's function. It invokes helper's function which I would like to start a polling routine to a server-side controller.

Client's code:

initiatePolling : function(cmp, callEvent) {
        var myFunction = function() {
            console.log('Inside myFunction');
            var action = cmp.get("c.myServerSideFunction");
            action.setCallback(this, function(response) {
                console.log("Inside myServerSideFunction callback");
                if (response.getState() === "SUCCESS") {
                    console.log("Success: " + response.getReturnValue());
                } else {
                    console.log("Error");
                }
            });
            $A.enqueueAction(action);
            setTimeout(myFunction, 1000);
        }
        myFunction();
}

Server's code:

@AuraEnabled
public static String myServerSideFunction() {
    return 'Server-side callback';
}

The problem is that after clicking the button, in a console I receive the following messages:

Inside myFunction
Inside myServerSideFunction callback
Success: Server-side callback
Inside myFunction
Inside myFunction
Inside myFunction
etc...

It looks like the server-side callback is received only once. Why does it happen? How can I make it work?

4

Since the actions are asynchronous, they will not execute in the order you expect. Your code works, you just need to you leave your console open long enough and you will see batches of server side actions executed simoultaneously after some time. This is specified in the lightning components developer guide section under Calling a Server-Side Actions

$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.

This post answered by @martin --> Use of setCallBack() in Lightning can provide furhter details on using callback functions in lightning controllers and interacting with servers side actions

4
  • Thanks for the response. Do I understand correctly that there isn't any way of synchronous polling in Salesforce? I tried putting the setTimeout inside of the setCallback body but after that the function invokes only twice (where the second time gives only "Inside myFunction"). Feb 6 '18 at 14:13
  • correct, you cant synchronously call server side actions and expect the server to responf when you want due to the Architecture.
    – glls
    Feb 6 '18 at 14:18
  • But shouldn't it work after putting setTimeout inside of the callback's body? Thanks to that, in my opinion, next call should be invoked only after receiving a data from the server. Sadly the routine just stops its execution. Feb 6 '18 at 14:26
  • this post--> Use of setCallBack() in Lightning might be of interest to you
    – glls
    Feb 6 '18 at 14:47
4

So I've finally figured it out. It looks like it's possible to repeatedly poll the server-side controller.

For the first, I put setTimeout inside of the action's callback, at the bottom of function's body, to make it sure that the next invocation will happen after receiving server's response. But it wasn't enough since after a second invocation of myFunction the code stopped its execution. It turned out that there's a little section about a getCallback function at the bottom of the Calling a Server-Side Action article:

If your action is not executing, make sure that you’re not executing code outside the framework’s normal rerendering lifecycle. For example, if you use window.setTimeout() in an event handler to execute some logic after a time delay, wrap your code in $A.getCallback(). You don't need to use $A.getCallback() if your code is executed as part of the framework's call stack; for example, your code is handling an event or in the callback for a server-side controller action.

Another helpful article is Modifying Components Outside the Framework Lifecycle.

I wrapped setTimeout function in a getCallback and it finally started working:

Inside myFunction
Inside myServerSideFunction callback
Success: Server-side callback
Inside myFunction
Inside myServerSideFunction callback
Success: Server-side callback
Inside myFunction
Inside myServerSideFunction callback
Success: Server-side callback
...

Here's the proper code:

initiatePolling : function(cmp, callEvent) {
        var myFunction = function() {
            console.log('Inside myFunction');
            var action = cmp.get("c.myServerSideFunction");
            action.setCallback(this, function(response) {
                console.log("Inside myServerSideFunction callback");
                if (response.getState() === "SUCCESS") {
                    console.log("Success: " + response.getReturnValue());
                } else {
                    console.log("Error");
                }
                setTimeout($A.getCallback(myFunction), 1000);
            });
            $A.enqueueAction(action);
        }
        myFunction();
}
1
  • thank you so, so, so, so, so, much for this. Mar 7 '19 at 4:31

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.