THURSDAY, JANUARY 19, 2017

Display Messages With UI Notifications

Some time ago we showed you how to refresh the left navigation pane via a script. The server-side solution in that article utilizes ServiceNow’s UINotification object/class. On versions prior to Calgary, this is the Java class Packages.com.glide.ui.UINotification

There’s another use for UI notifications. In addition to refreshing the left navigator, the object can also be used to display informational messages. You’ve probably already seen these in your own instance. When you change update sets, the system reminds you by using a UI Notification similar to the one shown below:

Update Set Change

If you’re like me, you may have wondered how these notifications are created. Displaying a custom UI notification is slightly more complex than using the addInfoMessage() method provided by the GlideSystem (server) and GlideForm (client) classes. In return, it gives you some capabilities that aren’t otherwise available. These include options to set fade-in and fade-out effects and the ability to make the notification persistent or to close it after a user-specified interval. If you want to learn more about the various types of notifications available in ServiceNow, check out our UI Info and Error Message Cheat Sheet.

The example below uses the UINotification object to display a list of all fields that have been changed on an incident. I’d like to take credit for this solution, but it was actually my colleague Jim Coyne who did the heavy lifting. I’m most especially indebted to him for compiling the all-important list of option properties that determine how the notification behaves.

As with any undocumented API, ServiceNow could make changes to the UINotification class at any time that might break the functionality we’re describing. Also, ServiceNow Technical Support won’t give you any help if you have trouble with this. Be sure to keep those things in mind if you decide to use custom UI Notifications in your instance.

Creating The Notification

To create the UI Notification and its options, use a global UI Script:

‘Popup UI Notification’ UI Script
Name: Popup UI Notification
Active: true
Global: true
Description: Adds a popup UI Notification to the DOM. Can be called from any server-side script. For an example, see ‘Changed Fields UI Notification’ business rule on the Incident table.
Script:

//Ensure that the CustomEvent object exists
var intervalTest = setInterval(function(){
   if(typeof CustomEvent != 'undefined'){
      clearInterval(intervalTest);
      setCustomEvents();
   }
},500);

//Add the UI Notification to the DOM using the CustomEvent object
function setCustomEvents(){
   //Set the name of the notification
   var notifName = "demo_notification";
   CustomEvent.observe('glide:ui_notification.' + notifName,
   function(notification){
      var msgText = notification.getAttribute('text1'); //get the message text from the attribute passed in by the business rule
      var options = {}; //create a new object to store all of the message attributes.
      options.text = "<span style='color:red;'>" + msgText + "</span>";
      options.sticky = true;
      options.closeDelay = 5000;
      options.fadeIn = 500;
      options.fadeOut = 500;
      new NotificationMessage(options); //display the UI Notification
   });
}

The CustomEvent object takes two arguments:

  1. The ‘glide:ui_notification.‘ object. This object includes a mandatory property that defines its name. In our example we’ve used a variable to store the name, but it could also be added to the object as an explicit value. In that case, it would be written ‘glide:ui_notification.demo_notification’ (including the quotes).
  2. A function that defines the notification’s contents and display options. The display options determine how the notification will behave. The options should be defined as properties in their own options object within the function. Available options properties include:
    text: Required. The text of the message. You can include rich text formatting via standard HTML tags.
    sticky: Optional. If true, the notification persists until the user closes it by clicking the [x] icon. If false or omitted, the notification automatically closes after the specified closeDelay.
    closeDelay: Optional. Automatically closes the message after this number of milliseconds. If omitted, the message closes after about three seconds. If the sticky property is true, this option is ignored.
    fadeIn: Optional: Sets the fade-in time for the notification in milliseconds
    fadeOut: Optional: Sets the fade-out time for the notification in milliseconds if the sticky property is false/omitted. If the sticky property is true, this option is ignored.
Note that if fadeIn, fadeOut and closeDelay intervals are specified, they are additive. That is, the notification will be displayed for the total amount of time specified in all three properties.

The function uses the getAttribute() method to retrieve the information passed in from the server-side script which triggers the notification. If multiple attributes have been set in the server-side script, the UI Script will need additional getAttribute() method calls to retrieve each one.

Displaying the Notification

To display the notification, we simply instantiate, (create a new instance of) the UINotification object in a Business Rule (it may work in other server-side scripts but I haven’t tested that). For our example we’ll use a business rule that runs after the incident has been updated. Our script borrows code from a previous post about checking for modified fields on forms or records.

‘Changed Fields UI Notification’ Business Rule
Name: Changed Fields UI Notification
Table: Incident [incident]
Active: true
When: after
Update: true
Script:

//First, get an ArrayList of all fields changed on the record
if (typeof GlideScriptRecordUtil != 'undefined') {
   var gru = GlideScriptRecordUtil.get(current);
} else {
   var gru = Packages.com.glide.script.GlideRecordUtil.get(current);
}

var changedFields = gru.getChangedFields(); //Get changed fields with friendly names

//Next, pass the values into the UI Notification we defined in the UI Script
var notification;
if(typeof UINotification != 'undefined') {
   notification = new UINotification('demo_notification'); //Calgary and later releases use the UINotification object call
} else {
   notification = new Packages.com.glide.ui.UINotification('demo_notification'); //For pre-Calgary releases, use the Java Package call
}

//create the message to be displayed
var messageText = gs.getUser().getDisplayName();
messageText += ' modified the following fields on : ';
messageText += current.number;

/*
Assign the message text to the 'text1' attribute. Additional attributes can be passed into the UI notification. Just be sure each one is accounted for in the UI Script via getAttribute() method calls.
*/

notification.setAttribute('text1', messageText + changedFields);
notification.send();

The key items in the business rule’s script are:

  • The new UINotification object call that specifies the object we defined in the UI Script (‘demo_notification’)
  • The setAttribute() method that passes specific information into the notification
  • The send() method that triggers the actual display of the notification.

To see the notification, open any Incident and modify one or more fields, then Save or Update it.

Incident field changes

Once the UI Script is defined, it can be reused as many times as needed. Just call it from any business rule and pass information to it using the setAttribute() method.

16 Comments

Oliver 18-02-2014, 07:02

Very nice, but how do you guys always find out what is included in the classes like UINotification and GlideScriptRecordUtil? Is there some kind of web decompiler?

Reply
Jim Pisello 18-02-2014, 07:28

Mostly its just a lot of sleuthing Oliver– Examining other out-of-box scripts that use the function can give you clues, especially if the function is defined in a Script Include. Using your browser’s developer/web tools to view the source for the page is also a good way to find information about some of these undocumented functions. Sometimes you can even get information from ServiceNow technical support, though they’re always quick to note that these functions are not officially supported. Really it just boils down to doing a lot of digging and then experimenting with things until you get it right.

Reply
Paul Ciarfella 18-02-2014, 14:34

One needs to be careful though when using these undocumented API’s. ServiceNow can change the API between releases since its not a supported public interface. I was bitten by that on an upgrade from Aspen to Berlin.

Reply
Jim Pisello 18-02-2014, 14:43

Right you are Paul, and thanks for that reminder. I’ve added an advisory note to the article.

Reply
Steven Villilo 25-02-2014, 22:44

Great stuff Jim, There is a Syntax error on Line 17 “UI SCRIPT”

options.text = “” + msgText + “”;

Reply
Jim Pisello 26-02-2014, 06:43

Thanks Steven. I’ve updated the code.

Reply
Nick 11-04-2014, 12:10

Pretty sure this only works in BR’s. Tried Script include and scheduled job, no luck. Works fine in business rules though.

Reply
Jim Pisello 11-04-2014, 12:28

I suppose that’s what I get for assuming, Nick. Admittedly I haven’t tried this out anywhere other than in a business rule. I can’t think of any reason why it wouldn’t work in any other server-side script, but it’s certainly possible. I’ll update the post to note that.

Reply
Nick 11-04-2014, 12:42

I am trying to use this as a session timeout message, I am going to try a script action. I cannot use a business rule because I want this message to fire without a database action, from the server because I wanted to fire this before session timeout. Grr. this is driving me nuts.

n = new UINotification(‘demo_notification’);
n.send();

Any ideas would be great!!

Reply
Nick 13-04-2014, 20:23

Ok so for anyone that needs an idea for this here is what I did-

Global UI Script that runs on interval calling a script include Ajax, which in turn queries the v_user_session table, field ‘last_transaction’. Compare that to the current time, and then against whatever your system timeout property is. Ours is the default 30 minutes. If the difference is almost thirty minutes return the username from the user session table, and then invoke the n= new UINotification(answer + ‘ your session is about to expire, save your work ! ‘ ) from the UI Script. Only way I could figure to “schedule” this. Couldn’t get this to work in script action, script include , scheduled job. Just on the client (obviously) and business rules. If anyone knows why this only works in BRs that would be great to know!

Reply
Richard Selby 19-01-2016, 03:26

It works fine in a Script Include for me (on Fuji). You should reload the entire screen (not just the form) after adding the UI Script.

Reply
Shurik 18-04-2014, 07:46

Does someone try to use above UI Script and Business Rule? I created exactly the same items but had no luck with pop-up message displaying

Reply
Nadya 18-05-2015, 21:32

Hi!

Nice article.
I have tried this, but the notification only showed up for the Updater. I need to make the notification shown for the other agents (or a specific role).
Did I miss something?

Reply
Russell Miller 31-05-2015, 18:21

I have to add my voice to that one, it’s not clear how to control who will get the notification… other than that this is really useful.

Reply
Harel 17-04-2016, 10:00

Joining Nadya and Russell on that – is it possible to show such a notification to all connected users, and not only to the one who made the changes?

Reply
Jeff Schodde 02-06-2016, 21:45

I hope someone comes up with an easier way to do this. It seems like a lot of code for such a simple feature. Anyone?

Reply

Leave a Reply


Latest Comments

  • David: It appears that I can hit sys_properties table with REST. This works, but I haven’t yet discovered the...
  • Mark Stanger: Hey David, It doesn’t surprise me that scoped apps have made this more difficult. I’m not...
  • David: Mark, do you have an example of how to do this in a scoped app? It seems there are many hoops to jump through...
  • Mark Stanger: The only possibility is to create a system property to override this in your application. Check out the...