Calling Apex method at regular interval in lightning component

Calling Apex method at regular interval from Lightning Component

Recently, I was in need of Lightning Component, which can poll Apex class at regular interval and display status of some process running in background. Initially, I thought its very easy and straight forward. Just like we do in Visualforce, use window.setInterval method of Javascript and I came up with below code.

RefreshContactCounter.cls

/**
 * @Author		:		Jitendra Zaa
 * @Date		:		Nov-09-2016
 * @Desc		:		This class is used by LEX component - PollApexClass
 * 			:		It returns total number of contacts in system
 * */

public class RefreshContactCounter {
    
    @AuraEnabled
    public static Integer getContactCount(){
         AggregateResult[] groupedResults = [SELECT count(Id) totalCount FROM Contact];
		Object totalCount = groupedResults[0].get('totalCount');
        return (Integer) totalCount ;
    }

}

PollApexClass.cmp

 
 <aura:component controller="RefreshContactCounter">    
    <aura:attribute type="Decimal" name="contactCount" />
     <aura:handler name="init" value="{!this}" action="{!c.doInit}" /> 
<div class="slds"> 
<article class="slds-card slds-card--narrow">
<div class="slds-card__header slds-grid">
<header class="slds-media slds-media--center slds-has-flexi-truncate">
<div class="slds-media__figure">
                        <c:svg xlinkHref="/resource/SLDS_2_0_3/assets/icons/standard-sprite/svg/symbols.svg#contact" class="slds-icon slds-icon-standard-contact slds-icon--small" /> 
                    </div>
<div class="slds-media__body slds-truncate">

<h2>
                            <span class="slds-text-heading--small"> Total Contacts in system</span>
                        </h2>
                    </div>
                </header> 
            </div>
<div class="slds-card__body slds-align--absolute-center slds-text-heading--large"> {!v.contactCount }</div>
<div class="slds-card__footer"> Refresh rate - every 5 seconds </div>
        </article>        
    </div>    
</aura:component>

PollApexClassController.js

({
	doInit : function(component, event, helper) {
		helper.pollApex(component, event, helper);
	}
})

PollApexClassHelper.js

({
    pollApex : function(component, event, helper) { 
        helper.callApexMethod(component,helper);
        
        //execute callApexMethod() again after 5 sec each
        window.setInterval(helper.callApexMethod(component,helper), 
		5000,);      
    },
    handleResponse : function (response, component){
        var retVal = response.getReturnValue() ;
        component.set("v.contactCount",retVal); 
    },
    callApexMethod : function (component,helper){    
        var action = component.get("c.getContactCount");        
        action.setCallback(this, function(response) {
            this.handleResponse(response, component);
        });
        $A.enqueueAction(action); 
    } 
})

In above helper javascript file, we are using window.setInterval() method of Javascript, to call Apex class at interval of 5sec.

DemoApp.app

<aura:application >
    <ltng:require styles="/resource/SLDS_2_0_3/assets/styles/salesforce-lightning-design-system.css" />
 	<c:PollApexClass /> 
</aura:application>

If we try to run above application, it doesn’t work as expected and returns below error

Windows setInterval error in Lightning Component
Windows.setInterval() error in Lightning Component

After going through documentation, I came across this page, which hints how we can modify Lightning component’s content outside its lifecycle.

In PollApexClassHelper.js file, we just need to change method pollApex by below code :

pollApex : function(component, event, helper) { 
        helper.callApexMethod(component,helper);
        
        //execute callApexMethod() again after 5 sec each
        window.setInterval(
            $A.getCallback(function() { 
                helper.callApexMethod(component,helper);
            }), 5000
        );      
    }

Demo :

poll apex class in lex compressor


Posted

in

by

Comments

25 responses to “Calling Apex method at regular interval from Lightning Component”

  1. Ashwani Soni Avatar
    Ashwani Soni

    Superb finding! One of my Appexchange component uses similar real-time update approach. Will this approach show updated data without tap or click on component/window? Thanks for the share!

  2. Rajan Patil Avatar
    Rajan Patil

    Nice one…thanks for share..

  3. KidNiki Avatar
    KidNiki

    HI, this is great, very useful code, thank you!

  4. Chaithra K N Avatar
    Chaithra K N

    Will it work if we enable locker service?

    1. Jitendra Zaa Avatar

      yes, I have tested it !!!

  5. Topalovich Avatar
    Topalovich

    This is great, thanks for posting.

  6. Apoorv Jain Avatar
    Apoorv Jain

    Hi , Thanks for sharing this.Was very helpful.
    Also, I need to make a small change in this.
    Let say it the count record value = 40 , then this should stop calling or it should stop. I tried with :
    if(record count != 40)
    //run the code window.setInterval(
    else if(record count == 40)
    // do something else

    when I debug this , when the record count comes to 40 , still this is calling the apex action at 5 sec of interval.

    Can you please suggest some method to stop this time interval calling at some condtion.

    Thanks and regards
    Apoorv Jain

    1. Rohit Pund Avatar

      Hi Apoorva,

      Yes we can kill polling by using such condition. I tried below logic and it works well.

      pollApex : function(component, event, helper) {
      helper.callApexMethod(component,helper);

      //execute after 5 sec each till next case is not assigned
      var pollId = window.setInterval(
      $A.getCallback(function() {
      helper.callApexMethod(component, helper, pollId);
      }), 5000
      );

      },

      callApexMethod : function (component,helper,pollId){
      var action = component.get(“c.getContactCount”);
      action.setCallback(this, function(response) {
      this.handleResponse(response, component, pollId);
      });
      $A.enqueueAction(action);
      },

      handleResponse : function (response, component, pollId){
      var retVal = response.getReturnValue() ;
      component.set(“v.contactCount”,retVal);
      //logic to kill polling
      if(retVal > 40){
      //This will kill your batch job
      window.clearInterval(pollId);
      }
      }

      Please let me know if it solves your purpose. Cheers.

  7. Saurabh Singh Avatar
    Saurabh Singh

    Hi @Rohit Pund
    I tried implementing the code that you have mentioned but I am getting error at calling helper.callApexMethod(component, helper, pollId); For me its showing error “Cannot read property ‘callApexMethod’ of undefined”. I tried it changing to this.callApexMethod(component, helper, pollId); and then it says “helper.callApexMethod(component, helper, pollId);” is not a function.

    1. Manas Avatar
      Manas

      I’m getting the same error. This code is not working.

  8. Murali Avatar
    Murali

    Some issue in the code here.

    i have implemented the same logic for one of the component which is there on contact layout

    Step 1: user open a contact and did some actions and polling called
    Step 2: user went to account on the same browser tab
    Step 3: very immediately user come back to same contact where he did some actions last time

    in this case the polling method still calling and getting setcallback issue. if the time interval is more between contact to account to contact no issue is coming.

    I tried to find the polling apex id to kill the recursing job but it is null.

    Can you help to fix this

    1. Murali Avatar
      Murali

      I understand that polling method is keep on calling even we move to other tabs in the browser. The above code practically will not work. Is there any way we can do polling

      1. Rahul Avatar
        Rahul

        You could possible use . Store the poll ID in an aura attribute, and on tab change (in console) , it will destroy it!

        1. Murali Avatar
          Murali

          Rahul,

          Could you please provide how to kill when moved to other tab. I am new to lightning and I struck there

  9. Anketha Avatar
    Anketha

    Hi,
    I’m trying the below code. But it’s not working.
    Instead of just calling the function – DisplayBusinessHoursForOpenOrders(component), I want to refresh this function every 1000 ms which is not happening. These lines are commented because, they are not working. Can anyone please mention why this is not working.
    if(StoreResponse==false){
    /* window.setInterval(
    $A.getCallback(function() {
    this.DisplayBusinessHoursForOpenCases(component,helper);
    }), 1000
    ); */
    this.DisplayBusinessHoursForOpenOrders(component);
    }
    else{
    this.DisplayBusinessHoursForClosedOrders(component);
    }

    Regards,
    Anketha

  10. Hemant Singh Rana Avatar
    Hemant Singh Rana

    Thanks for this awesome approach. But I just want to understand one thing is there issue with any governor limit or any issue with performance as calling apex method every 5-10 sec will be a good approach or not. I am just thinking about this as I want to implement this functionality and need to be clear before implementing it. Thanks for you help…

    1. Andres D. Avatar
      Andres D.

      I have the same concern, any idea on this?

  11. Kalyan Avatar
    Kalyan

    Hi,

    I am having a problem. Below is the code.

    @AuraEnabled
    public static String calculateEstimate(String id, String sobjName){
    System.debug(‘sobjName::’+sobjName);

    String endPointURL=’https://pod2.sssss.com/icmx/jsp/sf/some_apis.jsp’;
    String API_VERSION=’15.0′;
    String baseURL= URL.getSalesforceBaseUrl().toExternalForm();
    String partnerServerURL=baseURL+’/services/Soap/u/’+API_VERSION+’/’+Userinfo.getOrganizationId();
    String businessToken =’7830133a9723db8c5a67c9a886418′;
    String requestBody=’sfSessionId=’+UserInfo.getSessionId()+’&sfServerUrl=’ + String.escapeSingleQuotes(partnerServerURL) + ‘&sfDomain=’ + String.escapeSingleQuotes(baseURL) + ‘&BizToken=’+businessToken+’&sfPartnerServerUrl=’+partnerServerURL;
    System.debug(‘requestBody:>>’+requestBody);
    // System.debug(‘endPointURL:>>’+endPointURL);

    HttpRequest req = new HttpRequest();
    //req.setBody(requestBody);
    req.setEndpoint(endPointURL);
    req.setMethod(‘post’);
    Http h = new Http();
    HttpResponse res = h.send(req);
    System.debug(‘sobjName::’+res);
    System.debug(‘httpResponse:>>’+res.getBody().trim());

    return ”;
    }

    Here I am trying to fetch the sessionId in the jsp that is shown. In this case I am getting the sessionId as null in the JSP. Where when I call the same code without the @auraenabled annotation and remove the static reference, it is working fine.

    May I know if there is a way of getting the sessionId in the JSP?

    Thanks for your help in advance.

  12. Krishna Avatar
    Krishna

    I woukd like to do the same but I am worried about the total page performace. Will it hamper it in some way? also, due to this the page load time increases? Please let me know.

  13. viviramji Avatar

    Is there other way to solved this? I mean like Observer Patter just sent a notification to lightning component from apex method? I think a waste or resorce to listing all time new changes on backend. Thanks.

    1. Jitendra Avatar

      Platform event, Streaming API or empAPI Lightning component can be used. But they are very costly – only 50k notifications can be delivered in 24 hour. Even if its wastage of source, it does not count against any governor limit so I dont see any issue.

      1. srikanth.ValluriSrikanth Avatar
        srikanth.ValluriSrikanth

        Hi Jitendra,

        I have used the same setinterval function to refresh the records on lighting component for every 10 seconds, but after some time *nearly after 30 minutes) the page is not responding and not able to scroll through the page. Also I can see the API limits are completed. Is this the issue with Setinterval

  14. Mani Avatar
    Mani

    Hi Jitendra,

    I did come across a scenario wherein if the browser is minimized then the setInterval does freeze or there is a delay. Please let me know if there is a way to mitigate this use case.

    For example on the instance of using setInterval to display timer does not work accurately such as if window is in inactive state by minimizing the window.

    Appreciate your help.

  15. Mohit Avatar
    Mohit

    Good article , I want to know how we can achieve this in lWC

Leave a Reply to srikanth.ValluriSrikanth Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.