1

Is it possible to refresh a lightning component if any action is performed at the back-end. i.e I am currently displaying lightning component with list of cases, as soon as new case has been created at the back end, the front end lightning component should show new cases without refreshing the page. Is it something possible to implement with lightning component?

  • 4
    Our solutions to this so far have been to use a polling method. Simply call a method every few seconds using window.setTimeout. – sfdcfox Apr 19 '17 at 5:34
  • yes you can use window.setTimeout – Ratan Paul Apr 19 '17 at 5:41
  • No we cannot use setTimeout, we dont want to refresh component every 5 or 10 mins, we have to refresh component only when there is a change at the back end. – Chaithra K N Apr 19 '17 at 6:38
  • You could use the streaming API to do it and subscribe to object inserts and updates – Eric Apr 19 '17 at 7:18
  • My understanding is Lightning Data Service helps with this, but it's only in Developer Preview right now. Somebody at Dreamforce was talking about it, and it sounds like it allows you to "load" a record without writing your own Apex code, and if changes to that record occur in the backend, any components that loaded that record are automatically notified so they can act accordingly (refresh, etc). I haven't used it myself, but it sounds intriguing. More info at: developer.salesforce.com/docs/atlas.en-us.lightning.meta/… – Florissant53 Apr 20 '17 at 18:26
4

It's hard. If it's important, use the Force Streaming API.

You did not specify what action at the back end might trigger the refresh, but I'll assume there is a data change. The Force Streaming API is meant to do this, working around the main technology obstacle that is causing the impedance you encountered. Let me explain that comment:

The technology underlying the browser-based web grew up supporting scalable and secure requests from a client to a server. The client makes a request, the server provides the response, and then the network mostly forgets it ever happened. Security devices are constructed for this one-way request-response interaction. What you want is communication going the other way.

This leads people to offer the suggestion: "Just make a continuous sequences of requests." i.e. polling. This is where you see suggestions for setInterval in other answers here; and also where you'll see your application start to misbehave and your Salesforce allocated data calls exceeded causing panicked payments to upgrade Saleforce subscriptions when the application fails midday.

There is a widely-accepted technology solution to this, but it's typically really a pain to set up. However, it sounds like it is important to make this happen in your environment, which is exactly where this hard-to-approach technology fits. In the Salesforce stack, this solution has been available for years now under the name Force Streaming API. In order to understand how the API work under the covers, You might want to read up on WebSockets, Server-Side Events, and Long Polling.

Unfortunately, it's meant for Salesforce Classic, and others have been challenged to get it working with Lightning Components. Here's a good link to someone who has been successful: https://salesforce.stackexchange.com/a/184892/49942

2

You can do it, but it's not really straightforward. Basically, you can create a trigger on case objects and have that fire a platform event. Your component can listen for that event and force an update. For bonus points, your platform event could contain enough detail such that you don't actually need to roundtrip to the server to get the details for updating the table:

Create a trigger on Case objects, if you don't already have one:

trigger Cases on Case (after insert) {
    if(Trigger.isAfter) {
        System.debug('I will be replaced shortly!');
    }
}

Create a platform event (Setup > Data > Platform Events > New Platform Event)

  • Create the event (it's basically an object that defines the payload for the message)
  • Add fields to the event (eg., new Case ID, CaseNumber, and any other metadata you want to send). Just don't make it super big because that may be a performance issue if you have lots of active listeners

In my example, I'm calling my events Case Updated, so the API name becomes Case_Updated__e.

Create a method to build a new platform event:

public class ExampleClass {
    public static void publishCaseUpdateNotifications(List<Case> cases) {
        List<Case_Updated__e> notifications = new List<Case_Updated__e>();
        for (Case c: cases) {
            notifications.add(new Case_Updated__e(
                Case__c = (String)c.Id,
                CreatedByName__c = UserInfo.getName(),
                CaseNumber__c = c.CaseNumber
            ));
        }

        List<Database.SaveResult> results = EventBus.publish(notifications);

        for (Database.SaveResult result : results) {
            if (!result.isSuccess()) {
                for (Database.Error error : result.getErrors()) {
                    System.debug('Error returned: ' +
                        error.getStatusCode() +' - '+
                        error.getMessage());
                }
            }
        }
    }
}

Fire the event from your trigger:

trigger Cases on Case (after insert) {
    if(Trigger.isAfter) {
        // Send the list of cases (Trigger.new) to the example function
        ExampleClass.publishCaseUpdateNotifications(Trigger.new);
    }
}

So now we're at the point where an event will be fired after a case is inserted. Now we have to implement the other half of the equation, as has been described by other answers here. Using platform events makes the "streaming API" portion of the discussion a bit easier, which is why I chose this route as opposed to the base Streaming API functionality. Here are the basic steps:

Subscribe to your platform event:

https://trailhead.salesforce.com/en/modules/platform_events_basics/units/platform_events_subscribe

Here's some custom code I wrote, hopefully it will help you get started:

doInit : function(component, event, helper) {
    options.cometd.configure({
        url: 'https://<Salesforce_URL>/cometd/42.0/',
        requestHeaders: {
            Authorization: 'OAuth ' + component.get('v.sessionId')
        }
    });
    options.cometd.websocketEnabled = false;

    // Establish CometD connection
    if(options.cometd.isDisconnected()) {
        options.cometd.handshake(function(handshakeReply) {
            helper.handshakeCallback(component, helper, handshakeReply, options);
        });
    }
}

Here's the helper functions:

handshakeCallback: function(component, helper, handshakeReply, options) {
    if (handshakeReply.successful) {
        // console.log('Connected to CometD.');
        var newSubscription = options.cometd.subscribe('/event/Case_Updated__e',
            function(platformEvent) {
                console.log('Case update event received: ' + JSON.stringify(platformEvent));
                helper.onCaseUpdatedNotification(component, helper, platformEvent);
            }
        );
    }
}
,
onCaseUpdatedNotification: function(component, helper, platformEvent) {
    var that = this
    var eventDetails = platformEvent.data.payload;
    console.log("Updated case: " + eventDetails.Case__c);
}

I know there are some details missing (eg., downloading/referencing cometD in your component, getting the OAuth session ID), but I hope it helps with the overall structure.

1

Try event="force:showToast" It automatically call when you saved or change something

<aura:handler event="force:showToast" action="{!c.refreshRecords}"/>
  • wouldn't recommend this option, since force:showToast event can occur not only on data changes – ytiq Jun 3 at 12:16
0

You have to understand the architecture of Lightning Component development.

Your lightning components are not tightly coupled with the apex class or the database server. So the database server or any apex class will not be able to tell your lightning component that - hey! there is a change in case list view. Its up to your lightning component to ask the server that - do you have any change in case list view?

setTimeout or setInterval are your way out.

You can initiate the setInterval in your doInit method on aura:valueInit.

component:

<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>

Controller:

function : doInit(component, event, helper)
{
  setInterval(function(){helper.checkForChanges(component);}, 10000);
}

Helper:

function checkForChanges(component)
{
  //call your apex class to check for any changes
}
  • As i told you earlier we cannot have set Interval call to server every few seconds, it will lead to bad performance of the component, instead we want to show refreshed component once when there is a change data – Chaithra K N Apr 19 '17 at 9:45

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.