12

I am new to Lightning and I am completing Lightning Components Developer Guide. Here, in client-side controller, there is a method 'setCallBack()' used to call the method in server-side controller. I Googled for the detailed explanation of this method but could not find anything. Can anyone explain the all possible parameters of the method and other usages. Here is a sample code from Developer Guide.

({
"echo" : function(cmp) {
    // create a one-time use instance of the serverEcho action
    // in the server-side controller
    var action = cmp.get("c.serverEcho");
    action.setParams({ firstName : cmp.get("v.firstName") });

    // Create a callback that is executed after 
    // the server-side action returns
    action.setCallback(this, function(response) {
        var state = response.getState();
        // This callback doesn’t reference cmp. If it did,
        // you should run an isValid() check
        //if (cmp.isValid() && state === "SUCCESS") {
        if (state === "SUCCESS") {
            // Alert the user with the value returned 
            // from the server
            alert("From server: " + response.getReturnValue());

            // You would typically fire a event here to trigger 
            // client-side notification that the server-side 
            // action is complete
        }
        //else if (cmp.isValid() && state === "INCOMPLETE") {
        else if (state === "INCOMPLETE") {
            // do something
        }
        //else if (cmp.isValid() && state === "ERROR") {
        else if (state === "ERROR") {
            var errors = response.getError();
            if (errors) {
                if (errors[0] && errors[0].message) {
                    console.log("Error message: " + 
                             errors[0].message);
                }
            } else {
                console.log("Unknown error");
            }
        }
    });

    // optionally set storable, abortable, background flag here

    // A client-side action could cause multiple events, 
    // which could trigger other events and 
    // other server-side action calls.
    // $A.enqueueAction adds the server-side action to the queue.
    $A.enqueueAction(action);
}

})

1 Answer 1

36

Basically, the setCallback() function sets a function to run after the action finishes. You might be wondering why we can't just call getReturnValue() on the action right after enqueuing it and why the setCallback() function is even necessary. Let's see...

LightningApplication

<aura:application >
    <c:LightningComponent />
</aura:application>

ServerSideController

public class ServerSideController {

    @AuraEnabled
    public static String getAnAccountName(){
        list<Account> alist = [SELECT Name FROM Account LIMIT 1];
        if ( alist.size() == 0 ) {
            AuraHandledException e = new AuraHandledException('No Accounts Found');
            e.setMessage('No Accounts Found');
            throw e;
        }
        return alist[0].Name;
    }

}

LightningComponent

<aura:component controller="ServerSideController">
    <ui:button press="{!c.getAName}" label="Get A Name"/>
</aura:component>

LightningComponentController Take 1

({
    getAName : function(component,event,helper){
        var action = component.get("c.getAnAccountName");
        $A.enqueueAction(action);
        console.log(action.getReturnValue());  
        console.log(action.getState());        
    }
})

Here, we get the action, we enqueue it, and get the return value right after. The problem with this is that the action has only been enqueued. It hasn't actually returned with a value yet.

enter image description here

So, if the value hasn't been returned yet, why not just keep checking the state of the action to see when it is finished, and then get the value after?

LightningComponentController Take 2

({
    getAName : function(component,event,helper){
        var action = component.get("c.getAnAccountName");
        $A.enqueueAction(action);
        while (action.getState() != "SUCCESS" && action.getState() != "ERROR" && action.getState() != "ABORTED"){
            console.log("waiting...");
        }
        console.log(action.getReturnValue());
    }

})

This doesn't work out so well…

enter image description here

enter image description here

Clearly we are checking the status of action too often. What if we try checking the value less often, say once per second:

LightningComponentController Take 3

getAName : function(component,event,helper){
    var action = component.get("c.getAnAccountName");
    $A.enqueueAction(action);

    var intervalId;
    var checkTheAction = function(){
        console.log(action.getState());
        if (action.getState() === "SUCCESS" || action.getState() === "ERROR" || action.getState() === "ABORTED"){
            console.log(action.getReturnValue());
            window.clearInterval(intervalId);
        }
    };

    intervalId = window.setInterval(checkTheAction,1000);
}

enter image description here

It works now, but then what would the optimal value be for the interval? Rather than leave us to try to configure this ourselves, luckily we have callbacks. They can get us the value of the action right after it returns, without bogging the computer down while it's waiting.

LightningComponentController Take 4

({
    getAName : function(component,event,helper){
        var action = component.get("c.getAnAccountName");
        action.setCallback(this,function(response){console.log(response.getState());console.log(response.getReturnValue());});
        $A.enqueueAction(action);
    }
})

enter image description here


The setCallback() function has three possible parameters. There are the two that you are already using, and also from the documentation:

setCallback() has a third parameter that registers the action state that will invoke the callback. If you don't specify the third argument for setCallback() , it defaults to registering the SUCCESS and ERROR states. To set a callback for another state, such as ABORTED , you can call setCallback() multiple times with the action state set explicitly in the third argument. For example:

action.setCallback(this, function(response) { ...}, "ABORTED");

The action states that can be used for the third parameter being:

SUCCESS The action executed successfully
ERROR The server returned an error
ABORTED The action was aborted

ALL -- the same as undefined, covers SUCCESS, ERROR and INCOMPLETE
INCOMPLETE

There are two other possible values for the action state, but they cannot be used as the third parameter for the setCallback() function:

NEW The action was created but is not in progress yet
Something has gone wrong. Action.setCallback(): Invalid callback name 'NEW'

RUNNING The action is in progress
Something has gone wrong. Action.setCallback(): Invalid callback name 'RUNNING'

8
  • Hi, Martin! Thanks for the reply. So, setCallBack() will be run after the server-side controller method has been executed. And the function mentioned as a parameter inside setCallBack() is for further processing on the output returned from the server-side method. Right? And one more thing, first parameter in above-mentioned example - 'This' refers to the component and 'response' param inside second function parameter is the response returned from the server-side method? Jul 22, 2016 at 13:21
  • 2
    setCallBack() itself is run right away. It's the function that it takes as it's second parameter that is run after the action completes.
    – martin
    Jul 22, 2016 at 13:38
  • I believe response is the action after the callout, and this is the global window object.
    – martin
    Jul 22, 2016 at 13:52
  • Thanks martin. Amazing explanation and effort. So, what 'This' is used for here? Jul 22, 2016 at 13:53
  • To be honest, I'm not sure that it does have a use... I've tried using undefined as the first parameter and everything seems to work fine; at least with what I've tried.
    – martin
    Jul 22, 2016 at 14:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .