Wednesday, October 11, 2017

Refresh VisualForce Page with Platform Events

Problem Statement 

A visual force page is embedded inside the standard page layout to display additional information from third party application as below.

A few use cases :
- Let's say there is change inside third party application content and we want to refresh the entire page
- If third party application is making change to sales force data on this page using API and we need to refresh the page



A few failed solutions

1) If third party application is rendered inside the iframe, we can not access the parent salesforce page.

E.g. if we try one of the below we get the error message, as salesforce will prevent third party iframe to access the parent page.

 window.parent.location.href = URL  
 parent.location.href=parent.location.href  
 parent.location.reload();  
 window.parent.location.href = window.parent.location.href  

error message:

 Unsafe JavaScript attempt to initiate navigation for frame with URL 'https://c.na59.visual.force.com/servlet/servlet.Integration?lid=066f4000001yE8F&ic=1&...'.   
 The frame attempting navigation is neither same-origin with the target, nor is it the target's parent or opener  


2) Polling : in parent visualforce page we can constantly do polling on server side to listen for changes and refresh the VF page as needed. Polling in general is not good idea and not very scalable.




Platform Event to Rescue

Event based solution comes quite handy here, where we can publish the event on server side and visualforce page can listen to event and on right criteria, it can alert the end user on change or refresh the page so that we can see the fresh data.

Platform event is glorified version of streaming api, and we can get more details on a separate post here.



Solution:

1. Create platform event
2. Upon change, publish event using rest api or on Apex
3. On visualforce page, listen to those event and refresh the page




Create platform event 

  • Essentially created two attributes (ObjectName__c and RecordId__c) so that we can publish the event having those attributes





Publish event using rest api or on Apex


1) Publish via Apex
  • Publish event call doesn't fail, hence we have to go through the results
  • Also publish call doesn't participate in transaction, meaning if transaction has to fail, event will still publish

 List<UpdateObjectEvent__e> events = new List<UpdateObjectEvent__e>();  
 UpdateObjectEvent__e event = new UpdateObjectEvent__e(objectName__c='Account', recordId__c='1234');  
 events.add( event );  
 List<Database.SaveResult> results = EventBus.publish(events);  
 if( results != null && results.size() > 0 ) {  
   for (Database.SaveResult sr : results) {  
     if (sr.isSuccess()) {  
       System.debug('Successfully published event. ' + results.size() );  
     } else {  
       for(Database.Error err : sr.getErrors()) {  
         System.debug('Error returned: ' + err.getStatusCode() + ' - ' + err.getMessage());  
       }  
     }  
   }  
 } else {  
   System.debug(' Noting is published. ');  
 }  
   

2) Publish via Rest API

Endpoint  : /services/data/v40.0/sobjects/UpdateObjectEvent__e/
Payload    : { "RecordId__c" : "123455634343", "ObjectName__c" : "Account" }





Listen to event on Visualforce Page 

We can use cometD library to listen to the event, I had to write customer wrapper (cometdCustom.js) to greatly simply the visualforce page. 




Source code 
It can be found at : https://github.com/c-shah/salesforce-streaming


No comments: