function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
louisa barrett 7louisa barrett 7 

How to stop all instances of a component listening for a platform event

Hi All,

On the opportunity record page I have an Aura component which has a Lightning:DataTable that displays all open tasks that meet a certain criteria. Also on the opportunity record page there is an Actions & Recommendations component which has access to 5 quick actions which create a task. What I want to be able to do is when a new task is created, the datatable to automatically refresh. I've tried using platform events(which this is the first time I've used them, so not really too sure what I'm doing). I've got an If statement in the callback to check if the task whatId matches the record Id, but this still means that every opportunity that is open on a tab is listening for the event. Not all opportunities have the data table component on the record page, and it doesn't seem that the subscription is destroyed when the tab is closed.
How do I unscribe to the event when the tab is closed? If the page is refreshed then it seems to be fine.
If there is another way to do this I'd be more than grateful for suggestions

Task Trigger Handler Code:
Private void psTaskCreated(Task[] tasks)
    {
        List<Task_Creation_Event__e> taeList = new List< Task_Creation_Event__e>();
        for(task tsk : tasks)
        {
            Task_Creation_Event__e taskEvent = new Task_Creation_Event__e();
            if(tsk.whatId != null && tsk.WhatId.getSObjectType() == Opportunity.sObjectType && tsk.Project_Task__c)
            {
                Task_Creation_Event__e tce = new Task_Creation_Event__e();
                tce.Opp_Id__c = tsk.WhatId;
                taeList.add(tce);  
            }
        }
        //Publish event
        try{
            if(taeList.size()>0)
                EventBus.publish(taeList);
        }catch(Exception e){
            throw new auraHandledException('Broken!');
        }
    }

Component:
<aura:component controller="OpportunityController" implements="flexipage:availableForRecordHome,force:hasRecordId" access="global" >
    <aura:handler name="init" action="{!c.doInit}" value="{!this}"/>
    <aura:attribute name="mydata" type="Object"/>
    <aura:attribute name="mycolumns" type="List"/>
    <aura:attribute name="listSize" type="integer"/>
    <aura:attribute name="draftValues" type="Object" default="[]"/>
    <aura:attribute name="Task" type="Task" default="{'sObjectType':'Task'}"/>
    <aura:attribute name="showSpinner" type="boolean" default="false"/>
    <lightning:empApi aura:id="empApi" />

    <div>
        <lightning:notificationsLibrary aura:id="notifLib"/>
            <aura:if isTrue="{!v.showSpinner }">
                <lightning:spinner alternativeText="Loading" />      
                <aura:set attribute="else">              
                    <!--To Do List Table--> 
                    <div class="slds-m-top--none slds-box slds-theme_default" >
                        <div class="slds-align_absolute--left">
                            <div class="slds-text-heading_small slds-text-color_default">       
                                Things I need to do ({!v.listSize})
                                <lightning:buttonicon iconName="utility:refresh" alternativeText="Refresh" 
                                                      variant = "brand" class=" slds-button_icon-x-small"
                                                      onclick="{!c.doInit}"/>
                            </div>
                        </div>
                        <div style="height: 175px;">
                            <lightning:datatable data="{! v.mydata }" 
                                                 columns="{! v.mycolumns }"
                                                 keyField="Id" 
                                                 draftValues="{!v.draftValues}"
                                                 onrowaction="{!c.handleRowAction}"
                                                 onsave="{!c.handleSaveEdition}"/> 
                        </div>
                    </div> 
                </aura:set>
            </aura:if>
    </div>
</aura:component>

Controller:
//get tasks from apex controller
    doInit : function(component, event, helper) { 
        console.log('do init called');
        var channel = '/event/Task_Creation_Event__e';
        const replayId = -1;
        const empApi = component.find("empApi");
        
        //A callback function that's invoked for every event received
        const callback = function (message) {
            var msg = message.data.payload;
            console.log('msg = '+JSON.stringify(msg));           
            console.log('Message returned : ' +msg.Opp_Id__c );  
if(msg.Opp_Id__c === component.get("v.recordId"))
            {
                console.log('Fetch tasks about to be called');
                helper.fetchTasks_Active(component);
            } 
        };
        // Subscribe to the channel and save the returned subscription object.
        empApi.subscribe(channel, replayId, callback).then(function(newSubscription) {
            console.log("Subscribed to channel 1" + channel);
        });
        const errorHandler = function (message) {
            console.error("Received error ", JSON.stringify(message));
        };
        empApi.onError(errorHandler);
        helper.fetchTasks_Active(component);
    },

Helper:
fetchTasks_Active : function(component){
        var actions = [
            {label: 'Show comments', name:'show_comments'},
            {label: 'Complete task', name:'complete_task'},
            {label: 'View task', name:'view_task'}       
        ];
        component.set('v.mycolumns', [
            {label: 'Due Date', fieldName: 'ActivityDate', type: 'date', editable:'true'},
            {label: 'Task Type', fieldName: 'Task_Type__c', type: 'text'},
            {label: 'Subject', fieldName: 'Subject', type: 'text', editable:'true'},
            {label: 'Comments', fieldName: 'Description', type: 'text', wrapText: true, editable:'true'},
            {label: 'Contact', fieldName: 'WhoName', type: 'text'},
            {label: 'Status', fieldName: 'Status', type: 'text'},
            {type: 'action', typeAttributes: {rowActions: actions}}
        ]);
        
        var action = component.get("c.fetchOpenProjectTasks");
        action.setParams({
            "oppId": component.get("v.recordId")
        });
        action.setCallback(this, function(result){
            var serverState = result.getState();
            console.log('Server state = ' + serverState);
            console.log('Fetch active tasks');
            var res = result.getReturnValue();
            console.log('res result');
            console.log(res);
            if (component.isValid() && serverState === "SUCCESS"){
                component.set("v.listSize",res.length);
                var rows = res;
                for (var i = 0; i < rows.length; i++) 
                { var row = rows[i];
                 if(row.Who)
                 {
                     row.WhoName = row.Who.Name;
                     if(row.TaskRelations.length >1)
                     {
                         var relatedWho = row.TaskRelations.length -1;
                         row.WhoName = row.Who.Name + ' +' + relatedWho.toString();
                     }
                 }
                }
                component.set("v.mydata",res);
            }
            else if (serverState === "ERROR") {
                var errors = result.getError();
                console.log('There are errors');
                console.error(errors);
                if(errors){
                    if(errors[0] && errors[0].message){
                        self.fetchErrors(component, errors, self);
                    }
                }
            }
        });
        $A.enqueueAction(action);    
    },
Many thanks
 
ShivankurShivankur (Salesforce Developers) 
Hi Louisa,

You can try something like below in your code to unsubscribe to the event:
empApi.subscribe(channel, replayId, subscribeCallback).then(function(subscription){
        component.set('v.subscription', subscription)
    })
     empApi.unsubscribe();
},
For more detailed information refer to below link:
https://trailhead.salesforce.com/content/learn/projects/workshop-platform-events/platform-event-subscribe

Hope above information helps, Please mark as Best Answer so that it can help others in the future.

Thanks.