9

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?

5
  • 5
    Our solutions to this so far have been to use a polling method. Simply call a method every few seconds using window.setTimeout.
    – sfdcfox
    Commented Apr 19, 2017 at 5:34
  • yes you can use window.setTimeout
    – Ratan Paul
    Commented Apr 19, 2017 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. Commented Apr 19, 2017 at 6:38
  • You could use the streaming API to do it and subscribe to object inserts and updates
    – Eric
    Commented Apr 19, 2017 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/… Commented Apr 20, 2017 at 18:26

4 Answers 4

8

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
  • I've solved the problem using the above approach. For streaming channel i've used Platform Event and in place of Aura component I've used LWC with empApi module in order to listen to the event messages. Works fine and I couldn't think of any other solution than streaming channels.
    – Sagnik
    Commented Jun 1, 2022 at 14:57
5

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

1
  • 1
    Andrew Fawcett also has a component solution for Streaming API. His implementation example uses a Platform Event but is also compatible with PushTopic. github.com/afawcett/streamingcomponent
    – Charles T
    Commented Dec 9, 2017 at 1:49
2

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

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

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
}
1
  • 1
    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 Commented Apr 19, 2017 at 9:45

You must log in to answer this question.

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