6

The ultimate objective is to detect if a visualforce page (or the lightning component embedded within it) is already being viewed/used by a user when someone else opens it and subsequently restrict edit'ability as needed.

I started off looking into Salesforce Platform Events, but am open to better approaches.

Referencing Platform Event Notifications in a Lightning Component and lightning:empApi documentation here, I was able to publish/subscribe to platform events in Lightning Experience without issues.

However, when I dropped the same component onto a Visualforce page (Lightning Out), empApi.subscribe() in ControllerJS (please see below) doesn't get called at all, resulting in subscription service to not work...? I don't see exceptions anywhere either. Is this a bug or could I be missing something?

I was hoping to utilize the stateful nature of lightning component UI and pair it with init and change events in component to capture and restrict access based on who is viewing the page.

Because I couldn't get above to work, another way would be to subscribe to platform event notifications with Apex Triggers, BUT wouldn't that require me to create a separate object to track who opened the page first and surround my logic around that object? Now I am asking myself, why even use platform events if that is the case (and make do with just a custom object to log who is viewing the page)? So, more importantly, are platform events the right solution in this situation?

Publisher Class

public with sharing class PlatformEvents {

    public static String publish(String targetId, String entityName, String entityType){

        String returnMessage = null;

        if(String.IsNotBlank(targetId)){
            try{
                List<Platform_Event_Test__e> events = new List<Platform_Event_Test__e>();
                events.add(new Platform_Event_Test__e(Target_Id__c = targetId, Entity_Name__c = entityName, Entity_Type__c = entityType));

                system.debug(logginglevel.ERROR, '-------------------------------> PlatformEvents publish() 1: ' + targetId + ' ' + entityName + ' ' + entityType);
                List<Database.SaveResult> publishResult = EventBus.publish(events);

                for(Database.SaveResult result : publishResult) {
                    if(result.isSuccess())
                        returnMessage = 'SUCCESS';
                    else {
                        returnMessage = 'ERROR(S): ';
                        for(Database.Error error : result.getErrors())
                            returnMessage += (error.getStatusCode() + ' - ' + error.getMessage());
                    }       
                }
            } catch (Exception ex) {
                returnMessage = 'ERROR(S): ' + ex.getMessage() + ' - ' + ex.getStackTraceString();
                system.debug(logginglevel.ERROR, '-------------------------------> PlatformEvents publish(): ' + returnMessage);
            }
        }

        return returnMessage;
    }

}

Invoking Publisher like so (via Execute Anonymous in Developer Console):

String returnMessage = PlatformEvents.publish('0081A000117cQiI', 'TEST', 'TEST');
system.debug(logginglevel.ERROR, '------------> ' + returnMessage);

Subscriber component (PlatformEventSubscriber.cmp)

<aura:component implements="flexipage:availableForAllPageTypes" access="global" >

    <aura:handler name="init" value="{!this}" action="{!c.init}" />
    <aura:attribute name="targetId" type="String" />
    <lightning:empApi aura:id="empApi" />   

    targetId = {!v.targetId} <!-- This value prints in Lightning Experience, but not in a Visualforce page via Lightning Out -->

</aura:component>

Subscriber component ControllerJS:

    ({
        init : function(component, event, helper) {
            try{
                var empApi = component.find("empApi");

                console.log("-------------> In c:PlatformEventSubscriber.cmp controller init ");

                var errorHandler = function (message) {
                    console.log("-------------> Received error ", message);
                }.bind(this);
                empApi.onError(errorHandler);

                var channel = '/event/Platform_Event_Test__e';
                var replayId = -1;
                var callback = function (message) {
                    component.set("v.targetId", message.data.payload.Target_Id__c);
                }.bind(this);

                empApi.subscribe(channel, replayId, callback).then(function(value) {
                    //This line executes in Lightning Experience, but not in a Visualforce page via Lightning Out
                    console.log("-------------> Subscribed to channel " + channel);
                });
            } catch(err){
                console.log('-------------> init ERROR: ' + err + ' ** MESSAGE: ' + err.message + ' ** STACK: ' + err.stack);
            }
        }
    })

For your convenience, lightning dependency app to host Lightning Components in Visualforce page (LightningComponentApp.app):

<aura:application access="GLOBAL"  extends="ltng:outApp">
    <aura:dependency resource="c:PlatformEventSubscriber" />
</aura:application>

For your convenience, visualforce page (LightningComponentContainer.vfp):

<apex:page title="Platform Events Test" sidebar="false">
    <apex:includeScript value="/lightning/lightning.out.js"/>  

    <div id="contentDiv"/>

    <script>
        $Lightning.use("c:LightningComponentApp", function() {
            $Lightning.createComponent("c:PlatformEventSubscriber",
                {},
                "contentDiv",
                function(cmp) {
            });     
        });
    </script>
</apex:page>
5
  • Is it classic SF or lightning experience? Oct 30, 2018 at 17:40
  • Like I mentioned in OP, I was able to publish/subscribe to platform events in Lightning Experience without issues. However, when I dropped the same component onto a Visualforce page (Lightning Out), my subscriber component is not printing targetId at all. Oct 30, 2018 at 17:42
  • I meant was that VF page viewed insided lightning experince or classics? Oct 30, 2018 at 17:51
  • I 'previewed' the VF page while in Lightning Experience AND also after switching to Classic. Same thing, no value is returned. Oct 30, 2018 at 18:03
  • @LightningEvangelist What alternative did you use to make it work your component in both classic and lightning ?
    – Hunt
    Jul 23, 2020 at 5:28

1 Answer 1

7

lightning:empApi is not supposed to work using VF page/Lightning out.

If you see the Experience section in the documentation of this component, you will find as below. Only those components which has Lightning Out / Visualforce listed in the Experience section will work in that experience.

Experience

Lightning Experience, Salesforce Mobile App

enter image description here

3
  • I overlooked that part... thanks for pointing it out! Oct 30, 2018 at 18:57
  • @Kal You're welcome! That section on the documentation is actually very good when making a decision as where the component will work vs. not.
    – Jayant Das
    Oct 30, 2018 at 18:59
  • @JayantDas what could be the alternative to keep the component working in both classic and lwc with Event Notification
    – Hunt
    Jul 23, 2020 at 5:25

You must log in to answer this question.

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