[SalesForce] Action remains in queue in lightning component when launched from timeout function

I am actually using lightning components with VF, to allow my user to search for a particular account. According to the client spec, the user will only type their letters and the search result should appear. I'am actually implementing the debounce functionality because i do not what to pin my server at each keypressed letter, using javacript setTimeout function in my JS controller. But my action is stuck in the queue and do not get executed :

cmp codes :

<ui:inputText aura:id="xid-vl" class="slds-input" label="Ville" keyup="{!c.showSearch}" updateOn="keyup"/>

controller codes :

showSearch : function(component, event, helper) {
    console.log("## show search");

    var delay = 1000;
    var timer = component.get('v.timer');

    clearTimeout(timer);
    timer = setTimeout(function(){
        console.log("starting search");
        helper.sendInfo(component);
    }, delay);

    component.set('v.timer', timer);
}

helper codes :

sendInfo: function(component){
    var vl = (component.find("xid-vl").get("v.value"));
    console.log("ville is :" + vl);

    if(vl != null && vl.length > 2){
        console.log("sending to server ");

        var action = component.get("c.getTest"); 
        //action.setParams({"name": rs,"other": ""}); 
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {  
                var result = response.getReturnValue();
                console.log("result :", result); 
            }
            else console.log('error :',action.getError());
            //component.set("v.showSpinner",false);

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

nothing happen, and no error get displayed. When using the salesforce lightning inspector, found that the action remians stucked in the queue with the State = NEW.

Am i missing something when enqueing the action ?

Best Answer

The behaviour is mentioned in the docs here

Use $A.getCallback() to wrap any code that modifies a component outside the normal rerendering lifecycle, such as in a setTimeout() call.

The $A.getCallback() call ensures that the framework rerenders the modified component and processes any enqueued actions.

Hence use that in your code like below

 var delay = 1000;
 var timer = component.get('v.timer');
 window.setTimeout(
 $A.getCallback(function() {
 if (component.isValid()) {
    helper.sendInfo(component);
  }}),
  delay);
 component.set('v.timer', timer);
}
Related Topic