Real-Time Notifications in Service , Employee or any customized Portal
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎11-28-2024 10:01 AM - edited ‎12-29-2024 01:44 AM
Implementing Real-Time Notifications (Web Socket-recordWatch )in the Service Portal
In ServiceNow, notifications play a critical role in keeping users informed about updates, tasks, and important changes. However, notifications in the Service Portal are not natively integrated as system notifications. They are delivered live via WebSockets, removing the need for manual refreshes or polling to display the latest notifications. This article explores how to implement real-time notifications in the Service Portal, using a combination of UI components, Business Rules, Script Includes, and custom logging.
Key Features:
- Live Notifications: Notifications are delivered in real time, ensuring users receive updates immediately without the need to refresh the page.
- User-Specific Notifications: Notifications are dynamically tailored for the user, with specific recipient fields, notification content, and language support.
- Multilingual Support: Dynamic content is supported in multiple languages, such as English and Arabic, based on the user’s language preference.
Step-by-Step Implementation
1. Create a Widget for Notifications
First, create a widget in the Service Portal that displays notifications and allows users to mark notifications as read (either for specific ones or all). This widget will render the notification panel, which includes:
- A notification icon in the header.
- Notification content displayed dynamically based on the user's unread notifications.
- Mark As Read for a specific notification.
- Mark All as Read for all user notifications.
HTML Code for Widget:
Client Script:
api.controller=function($scope, $location, $window, spUtil, amb, $http, spAriaUtil, $timeout, spNavStateManager, i18n) { /* widget controller */ var c = this; c.markNotificationAsRead = function(notificationId) { $('.notfication__panel').toggleClass('notfication__panel--active'); c.server .get({ action: "markAsRead", notificationId}) .then(function (response) { c.data.userNotifications = response.data.userNotifications; }); } c.markAllNotificationAsRead = function() { $('.notfication__panel').toggleClass('notfication__panel--active'); c.server .get({ action: "markAllAsRead"}) .then(function (response) { c.data.userNotifications = response.data.userNotifications; c.data.availUnRead = response.data.availUnRead; }); } spUtil.recordWatch($scope, $scope.data.table , $scope.data.filter , function(name) { spUtil.update($scope).then(function(){}); }); }
Server Script:
(function() { data.disableRecordWatcher=false; data.redirectPage = options.redirectPage|| 'ucp_standard_ticket' var util = new I18nUtils(); data.language = util.getLanguage(); data.table='u_portal_notifications_log'; data.filter='assigned_to='+gs.getUserID() data.disableRecordWatcher=false; var complainUtils = new global.GlobalComplaintUtils() ; if (input){ if (input.action === "markAsRead" && input.notificationId) { var notficationGR = new GlideRecord(data.table); notficationGR.get(input.notificationId); notficationGR.u_ucp_isreaded = true; notficationGR.update(); } if (input.action === "markAllAsRead") { var allNotficationGR = new GlideRecord(data.table); allNotficationGR.addQuery('assigned_to',gs.getUserID()); allNotficationGR.addQuery('u_ucp_isreaded','false'); allNotficationGR.query(); while(allNotficationGR.next()){ allNotficationGR.u_ucp_isreaded=true; allNotficationGR.update() } } } var notficationsMessage = new GlideRecord(data.table); notficationsMessage.addQuery('assigned_to',gs.getUserID()); if(data.language=='en') notficationsMessage.addEncodedQuery('u_ucp_content_bodyISNOTEMPTY^ORu_ucp_content_headerISNOTEMPTY'); else notficationsMessage.addEncodedQuery('u_ucp_content_body_arabicISNOTEMPTY^ORu_ucp_content_header_arabicISNOTEMPTY'); notficationsMessage.orderByDesc('sys_created_on'); notficationsMessage.setLimit(30); notficationsMessage.query(); var userNotifications =[] ; data.availUnRead=false; while(notficationsMessage.next()){ if(notficationsMessage.u_ucp_isreaded.getValue()==0) data.availUnRead=true; userNotifications.push({ 'sys_id': notficationsMessage.sys_id.getDisplayValue() , 'header' : notficationsMessage[data.language=='en'?'u_ucp_content_header':'u_ucp_content_header_arabic'].getDisplayValue(), 'body' : notficationsMessage[data.language=='en'?'u_ucp_content_body':'u_ucp_content_body_arabic'].getDisplayValue(), 'isReaded' : notficationsMessage.u_ucp_isreaded.getValue(), 'complaintSYSID' : notficationsMessage.u_instance.sys_id.getDisplayValue(), 'date' : complainUtils.getTimeElapsed(notficationsMessage.sys_created_on,data.language) }) data.userNotifications = userNotifications ; } })();
2. Create a Table to Log Notifications
To track and manage the notifications, create a table with the following fields:
- assigned_to: The recipient of the notification.
- u_instance: A reference to the task table (e.g., Incident, Change).
- u_ucp_content_header: The notification's header (in English).
- u_ucp_content_header_arabic: The notification's header (in Arabic).
- u_ucp_content_body: The notification's body content (in English).
- u_ucp_content_body_arabic: The notification's body content (in Arabic).
- u_ucp_isreaded: Indicates whether the notification is read (true/false).
3. Create a Business Rule to Log Notifications
Create a Business Rule that triggers when an event occurs, such as an incident update or a task assignment. This rule will log the notification in the table we created earlier.
Business Rule Script:
(function executeRule(current, previous /*null when async*/) { var notificationGR = new GlideRecord('u_portal_notifications_log'); notificationGR.initialize(); // Set the fields based on the task's data notificationGR.assigned_to = current.assigned_to; // or other user-specific field notificationGR.u_instance = current.sys_id; notificationGR.u_ucp_content_header = 'New Notification Header'; // Customize based on the use case notificationGR.u_ucp_content_header_arabic = 'عنوان الإعلام بالعربية'; notificationGR.u_ucp_content_body = 'The body content of the notification in English.'; notificationGR.u_ucp_content_body_arabic = 'Ù…ØØªÙˆÙ‰ الإعلام بالعربية.'; notificationGR.u_ucp_isreaded = false; // Set to false when creating new notifications notificationGR.insert(); })(current, previous);
4. Triggering Notifications via Script Includes
To dynamically trigger notifications based on events, create a Script Include that can be used by various parts of the application (like workflows, Business Rules, or background scripts) to send notifications in real time.
Script Include Example:
var NotificationHelper = Class.create(); NotificationHelper.prototype = { initialize: function() {}, // Method to send a notification sendNotification: function(userId, taskId, contentHeader, contentBody) { var notificationGR = new GlideRecord('u_portal_notifications_log'); notificationGR.initialize(); notificationGR.assigned_to = userId; notificationGR.u_instance = taskId; notificationGR.u_ucp_content_header = contentHeader; notificationGR.u_ucp_content_body = contentBody; notificationGR.u_ucp_isreaded = false; notificationGR.insert(); }, type: 'NotificationHelper' };
Conclusion
Implementing real-time notifications in the ServiceNow Service Portal using WebSockets ensures that users are always informed about the latest updates, tasks, and changes in a dynamic way. By leveraging a combination of widgets, Business Rules, Script Includes, and custom logging, you can create an efficient and effective notification system that improves user engagement and response times. With the flexibility to customize notifications in multiple languages, such as English and Arabic, you can meet the needs of diverse user groups. This approach also eliminates the need for manual refreshes, allowing for a smoother and more user-friendly experience in the Service Portal.
- 1,637 Views
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎02-18-2025 02:41 AM
Very helpful thanks' for sharing