Sending Events between Active Sessions with JavaScript

 
JavaScript can be used to send an event (optionally including data) to any session that is currently active and listening for that event. This could be used to enable collaborative working between multiple agents on a shared task, or to allow real-time in-Script notification and updates to groups of agents by a manager or supervisor.
 
There are three functions required for this:
  •  Script.Events.Fire "fires" an event that is accessible to all sessions that are open and listening for that event at the moment it is fired.
  •  Script.Events.AddListener specifies a "callback" function that will be executed upon the receipt of an event matching its specified filters.
  •  Script.Events.RemoveListener removes a previously-defined listener.
 

How To

Inside any JavaScript-manipulating Field (Calculate, JavaScript, JavaScript - Button), use the functions specified below.
 
When firing an event, all currently active listeners with a matching eventName and reference (if specified) will have their action triggered.
 
As events are shared across the entire Scripting system, care should be taken choosing the eventName to avoid accidentally triggering events in an unexpected Script. The reference can then be used to further filter those interested in an event, e.g. the eventName may relate to the specific client or process being undertaken, and the reference may include an incident ID so that only agents working on that incident receive it.
 
As with all other JavaScript behaviour within Scripting, listeners aren't persisted between pages. When the Script Page is navigated or reloaded, all existing listeners are removed, and will need to be recreated (if desired).
 
Additionally, fired events are only delivered to matching listeners that are active at the moment that the event is fired; there is no "queue" or cached list. Events are fundamentally transient, and aimed at updating a Page (or providing notifications to an agent) post-Page load.
 
These factors combined mean that if running an ongoing process where you may want to listen for events across multiple Pages in a Script, the process needs to be designed so that this period when events aren't received is handled - for instance, by having each Page load the current state of the process at the same time as it registers for events, ensuring that any changes that occurred during Page transition have been captured.
 
Firing Events
The syntax for firing an event is:
Script.Events.Fire(eventName, reference, data);
 
Name
Required / Optional
Explanation
eventName
Required
This is a string which serves as the primary filter to determine which listeners will react to this event.
reference
Optional
This is a JavaScript object that, if provided, contains key:value pairs that must all be matched by listeners for them to react.
data
Optional
This is a JavaScript object that, if provided, will be available to the listener's "callback" function.
 
 
Listening for Events
On each Page, as many listeners can be created as desired, covering any eventName and reference - including multiple listeners utilising identical filters. These listeners are persistent for the lifetime of the current Page in the Script (unless removed), and all will be cleared when the Page is reloaded or navigated away from.
 
As a result of these two factors, it's recommended that listeners are created inside structures like Run Once or via automatic JavaScript - Button controls, to ensure that multiple listeners aren't inadvertently registered for identical filters, leading to multiple actions occurring when an event is received.
 
If you intend to remove a listener without reloading the page, then the listener's ID must be stored at the moment of creation to be passed into Script.Events.RemoveListener.
 
The syntax to add a listener is:
listenerId = Script.Events.AddListener(eventName, reference, callback);
 
Name
Required / Optional
Explanation
eventName
Required
This is a string which serves as the primary filter to determine which events this listener will react to.
reference
Optional
This is a JavaScript object that, if provided, contains key:value pairs that must all match a fired event for this listener to react. If an empty object or null is provided, then this listener won't apply any filtering beyond the eventName.
callback
Required
This specifies a "callback" function which will be executed whenever events matching the filter conditions are received.
 
 
Removing Listeners
Once a listener has been added to a Page, there are only two ways to stop listening for that event and reference: remove all current listeners by reloading or navigating the page, or use this function to remove a specific listener.
 
The syntax to remove a listener is:
Script.Events.RemoveListener(listenerId)
 
Name
Required / Optional
Explanation
listenerId
Required
This is a string of the listener ID for the listener to be removed, as returned when the listener was created.
 
 
 

Examples

Example 1 - Warehouse Stock Updates
In this example, a Script is created with a List Box that the agent selects a type of product from (e.g. lawn mower, pressure washer), with this selection then being used to filter a Table control's listed products and stock levels. The desire is that if all remaining stock of a product is claimed, then all agents who are currently inspecting products of that type will have a message displayed, and their Table control will be refreshed.
 
When loading the relevant Page, the Script would trigger the below JavaScript snippet to start listening for any events matching the product type they're viewing:
 
Script.Events.AddListener(
    "WarehouseAvailability",
    {ProductLine: [Product Type List Box]},
    function (eventData) {
        Script.Toast.Loading("Stock Update", eventData.ProductName + " is out of stock.", 5000);
        Script.Utils.GetCSObject([Product Stock Table]).click();
    }
);
 
 
When an agent selects the last of a particular item from the Table, the Script would trigger the below JavaScript snippet to inform anyone else who is also viewing the same type of products:
 
Script.Events.Fire(
    "WarehouseAvailability",
    {ProductLine: [Product Type List Box]},
    {
        ProductName: [Product Stock Table]
    }
);
 
 
Example 2 - Direct Update
In this example, the first agent is going to pass some information to a second agent who will perform a verification process in parallel in a different Script. Upon the second agent completing this verification process, they will then directly return the result to the first agent's Script in real-time.
 
The first agent logs the request to the second agent by some method passing their Session ID to be used as the reference for returning the response. As part of logging the request, the first agent will also register their listener to await a response that utilises their Session ID as the reference, with the callback function directly writing a value back to a Script Field. However, we will need to trigger a JavaScript - Button as part of the action for the agent to see the change to the Field's value (see Notes):
 
Script.Events.AddListener(
    "VerificationUpdate",
    {Session: [var_csSessionID]},
    function (eventData) {
        [Verification Status] = eventData.Verification;
        Script.Utils.GetCSObject([JavaScript Button - Verification Updated]).click();
    }
);
 
// And below is the content of our JavaScript - Button field
Script.Toast.Info("Request Verification Complete");
 
 
When the second agent selects the verification state, the Script would then trigger the below JavaScript snippet to return the final verification state back to the first agent's Script:
 
Script.Events.Fire(
    "VerificationUpdate",
    {Session: [Session Being Verified]},
    {
        Verification: [Verification Result]
    }
);
 
 

Notes

Listeners don't trigger Calculate fields on the page when they execute their "callback" function, nor do they trigger a visible page update. This means that any Fields that have their values updated by a listener will be visually unchanged until after Page Calculations are next run. If directly mapping data back to any Fields from the callback function, then the callback function should also .click() a Field that triggers Page Calculations, such as a JavaScript - Button.
 
No feedback is provided when removing a listener, nor error if providing a nonexistent or invalid identifier for removal.