Use of setCallBack() in Lightning

  • 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);
    }
    

    })

  • martin

    martin Correct answer

    5 years ago

    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'

    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?

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

    I believe `response` is the action after the callout, and `this` is the global window object.

    Thanks martin. Amazing explanation and effort. So, what 'This' is used for here?

    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.

    Ok. No worries..

    that was a great explanation. can u pls explain the second parameter - 'funtion(response)'.also comment the link to the documentation

    Hi Navneet, please find the link. Callouts to server-side in Lightning is asynchronous. So, When your request is processed and the response is returned, at that time function in second parameter will be executed. You can then do the further processing on the response.

License under CC-BY-SA with attribution


Content dated before 7/24/2021 11:53 AM