Inserting USD events into HTML javascript logic and acting upon it

One of the key benefits of having Unified Service Desk host web applications rather than just displaying them in an iframe within the web client is its inherent ability to perform bidirectional communication with the web application without modifying its source code.  This is particularly important when you don't have control over the development of the application either because it is built by a 3rd party or another department.  Even if you do have control, you'd have to figure out how to code your application differently depending on whether it is hosted within USD or not, which is not ideal. With an iframe, security limits you to pushing URL's, which is a very limited form of communication, unless the host and hosted applications can agree on a protocol such as the HTML 5 messaging protocol.  These are fine methods when you have the ability to define both applications, but not so good when you need to communicate with an application that cannot or will not be so cooperative.

Unified Service Desk, because it hosts the browser itself, has much more control than a simple iframe.  It can inject javascript to set values, modify functions, or cause HTML events such as button clicks.  But another important capability of Unified Service Desk is its ability to effectively tell an application (whether it really knows it or not) to notify it about events as well.  This can be quite useful for things such as intercepting click events and have them run action calls that might, say, automatically load a map with directions in another tab when an address was
saved on a web form.  You might also detect when data is changing in fields and fire an event up to USD to tell it about the new data and populate data parameters to share with other hosted controls.

To do this is relatively straight forward in concept but with intimate knowledge of how javascript works, can become quite powerful.

Our Example

Now let's suppose we have the following javascript function in a 3rd party web page that is hosted within USD.  You can load your browser's debugger to see the javascript code on the page.  It happens to be called when the user clicks a button in the page.

 function MyButtonWasClicked()
 {
 // the web application does something here.
 }

In my case, I still want the code inside MyButtonWasClicked() to run but I want USD to know when this function was called as well.  What we want to do is insert USD into the logic on the page without disrupting it's functionality.  To achieve this, we want to start by adding an action to the page's BrowserDocumentComplete or PageLoadComplete event in USD, whichever is appropriate.

HostedControl:
<My Hosted Control>

Action:
RunScript

Data:
var MyButtonWasClickedOld = MyButtonWasClicked; //save the old method
MyButtonWasClicked = function() // create a new version of the function
{
   window.open("https://event/?eventname=buttonclickevent&param1=value1"); // fire the event to USD
   MyButtonWasClickedOld(); // call our old method
}

 

This action will replace the current implementation of the MyButtonWasClicked() function within the page and only when USD loads it. Outside USD, it will continue to work as it always has.  When the user clicks the button, it will call the new version of the function and in this case will call window.open with a special syntax that I describe soon, followed by calling the old implementation of the function.  In this case, we are notifying USD of the event before running the old implementation.  You could easily reverse that behavior or even eliminate the old behavior if it was desired.

Window.open event syntax

When a page is requested that starts with the special syntax of https://event/?, USD interprets it as an event.  This special URL must always have a parameter called eventname.  This parameter indicates the name that will be used in the USD event configuration. 

Now in CRM, lets add an event to our hosted control to do something with this event.  Go to the Unified Service Desk events configuration link.

 

 

Click New to add a new event.

 

 

In the event's name, enter the name exactly the same as specified in the eventname parameter of the event URL.

 

 

The Hosted Application field should be populated with the hosted control that contains your web application that you injected the script and that will produce the event.  You can then save this and add Action Calls to this event as you see fit.  In this case, let's just plan to display the event parameter, param1, in a dialog box.  Click Add to create a new action call within your new event.

 

Hosted Control:
CRM Global Manager

Action:
DisplayMessage

Data:
text=My parameter is [[param1]]

 

Wrapping up

Now when you run Unified Service Desk and click the button within the web application, your event will be fired.  You will see the event line in the USD Debugger as well so it's a good way to make sure your event is properly firing.  Also, since your event is mapped to a configured USD event, your action call will run as well.  The parameters you supplied in your event URL are all passed to the action calls linked to the event you created so you can use them when creating your action calls. 

If you need to transfer a larger amount of information from the application to USD, passing it in the event is not going to work because of the limitations on the length of URL's.  A better approach would be to fire the event without the large data set, and call RunScript, have it assemble the data in javascript and return it from the RunScript call.

Hosted Control:
<My Hosted Control>

Action:
RunScript

Data:
function RetrieveLargeData()
{
  return largeDataVariable;
}
RetrieveLargeData();

 

When you add this action call to your event, it will obtain the largeDataVariable and return it to the $Return entry in the Data Parameter list.  This method can handle quite a large amount
of data.