Mastering GlideModal: A Practical Guide to Calling UI Pages in ServiceNow
In the dynamic world of ServiceNow development, creating engaging and user-friendly interfaces is paramount. While standard forms and lists are powerful, there are often scenarios where a more interactive, focused experience is needed. This is where GlideModal, ServiceNow’s built-in JavaScript API for displaying modal windows, shines. It allows us to seamlessly integrate custom UI Pages into our workflows, providing dynamic content and capturing user input without navigating away from the current page.
If you’re a ServiceNow administrator, developer, or aspiring professional, understanding how to effectively leverage GlideModal is a crucial skill. This article will guide you through the process of calling UI Pages with GlideModal, offering practical explanations, real-world examples, troubleshooting advice, and insights into its relevance in interviews.
Why Use GlideModal for UI Pages?
Before diving into the “how,” let’s briefly touch on the “why.” UI Pages in ServiceNow are essentially self-contained HTML pages with embedded Jelly, JavaScript, and CSS. They are incredibly flexible and can be used for a wide range of purposes, from simple confirmation dialogs to complex wizards and custom data entry forms.
GlideModal acts as the bridge, allowing you to invoke these UI Pages in a modal window. This approach offers several advantages:
- Improved User Experience: Modals provide a focused environment for tasks, minimizing distractions and guiding users through specific processes.
- Context Preservation: Users can remain on their current record or page while interacting with the modal, preserving their context.
- Dynamic Content: UI Pages can be dynamically generated, meaning the content of your modal can change based on the current user, record, or other business logic.
- Data Interaction: GlideModal allows for the passing of parameters to the UI Page and the retrieval of results, enabling two-way communication.
- Streamlined Workflows: Complex tasks can be broken down into smaller, manageable steps presented within modals, making them less daunting for end-users.
The Fundamentals: Understanding GlideModal
GlideModal is a client-side JavaScript API. This means it’s primarily used within client scripts, UI actions, UI policies, and other client-side scripts. The core function we’ll be focusing on is GlideModal.open().
The basic syntax looks like this:
GlideModal.open({
title: 'Your Modal Title',
contentURL: 'your_ui_page.do?sysparm_id={sys_id_of_record}',
onClose: function(result) {
// Callback function when the modal is closed
// 'result' might contain data passed back from the UI Page
}
});Let’s break down the key parameters:
title: A string representing the title that will appear in the modal’s header.contentURL: This is the most important parameter. It’s a URL that points to the UI Page you want to display. You can pass system parameters (likesysparm_id) to provide context to your UI Page.onClose: A JavaScript function that executes when the modal is closed. This is where you’ll often handle any data returned from the UI Page.
Calling a Simple UI Page: A Step-by-Step Example
Let’s create a practical scenario. Imagine you have a button on the Incident form that, when clicked, opens a modal displaying a simple “Thank You” message and prompting the user to confirm an action. We’ll need two components: the UI Page and a UI Action to trigger it.
Step 1: Create the UI Page
Navigate to System UI > UI Pages and click New.
- Name:
simple_thank_you_modal - HTML:
<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide:util">
<g:evaluate var="jvar_message" expression="RP.getWindowProperties().get('message')" />
<div>
<h3>${jvar_message}</h3>
<p>Thank you for taking this action!</p>
<button class="btn btn-primary" onclick="closeModal('success')">OK</button>
<button class="btn btn-default" onclick="closeModal('cancel')">Cancel</button>
</div>
<script>
function closeModal(status) {
GlideModal.get().destroy({
result: status // Pass back a status
});
}
</script>
</j:jelly>- Client script: (This section is optional for this basic example, but good to know where it goes.)
Explanation of the UI Page HTML:
<?xml version="1.0" encoding="utf-8" ?>and<j:jelly ...>: Standard Jelly and ServiceNow XML declarations.<g:evaluate var="jvar_message" expression="RP.getWindowProperties().get('message')" />: This is crucial for receiving data passed from the calling script.RP.getWindowProperties()accesses properties set when the modal was opened, and.get('message')retrieves the value associated with the key ‘message’.<h3>${jvar_message}</h3>: Displays the message passed into the UI Page.<button class="btn btn-primary" onclick="closeModal('success')">OK</button>and<button class="btn btn-default" onclick="closeModal('cancel')">Cancel</button>: These buttons call a JavaScript functioncloseModal(), passing a status.<script> function closeModal(status) { GlideModal.get().destroy({ result: status }); } </script>: This embedded script defines thecloseModalfunction.GlideModal.get()retrieves the current modal instance, and.destroy({ result: status })closes the modal and optionally passes aresultback to the calling script.
Step 2: Create the UI Action
Navigate to System UI > UI Actions and click New.
- Name:
Open Thank You Modal - Table:
Incident [incident] - Action name:
open_thank_you_modal - Form button: Check this box.
- Client: Check this box.
- Onclick:
openMyModal(); - Script:
function openMyModal() {
var gdw = new GlideModal({
title: 'Important Message',
contentURL: 'simple_thank_you_modal.do?message=' + encodeURIComponent('Welcome to the Incident Form!'),
onClose: function(result) {
if (result === 'success') {
alert('You confirmed the action!');
} else {
alert('You cancelled the action.');
}
}
});
gdw.render(); // Render the modal
}Explanation of the UI Action Script:
function openMyModal() { ... }: Defines the function that will be called by theonclickevent.var gdw = new GlideModal({...});: This is the modern, recommended way to instantiate GlideModal. It’s an object-oriented approach.title: 'Important Message': Sets the modal’s title.contentURL: 'simple_thank_you_modal.do?message=' + encodeURIComponent('Welcome to the Incident Form!'):simple_thank_you_modal.do: This is the URL to our UI Page. ServiceNow automatically appends necessary parameters likesysparm_processor.?message=' + encodeURIComponent('Welcome to the Incident Form!'): Here, we are passing a parameter namedmessageto our UI Page.encodeURIComponentis important to handle special characters in the message. Thismessageparameter will be accessible in the UI Page usingRP.getWindowProperties().get('message').
onClose: function(result) { ... }: This is the callback function. Theresultparameter will contain whatever was passed back by the UI Page’sdestroy()method (in our case, ‘success’ or ‘cancel’).gdw.render();: This method actually displays the modal.
Now, when you navigate to an Incident record and click the “Open Thank You Modal” button, you’ll see the modal pop up. Clicking “OK” will trigger the success alert, and clicking “Cancel” will trigger the cancel alert.
Passing Record-Specific Data to the UI Page
A common requirement is to display information from the current record within the modal. We can achieve this by passing the record’s sys_id or other field values as URL parameters.
Updating the UI Action
Let’s modify the UI Action script to pass the incident’s number and sys_id.
function openMyModal() {
// Get the current record's sys_id and number
var incidentSysId = g_form.getUniqueValue();
var incidentNumber = g_form.getValue('number');
var gdw = new GlideModal({
title: 'Incident Details: ' + incidentNumber,
contentURL: 'simple_thank_you_modal.do?sysparm_id=' + incidentSysId + '&incident_number=' + encodeURIComponent(incidentNumber) + '&message=' + encodeURIComponent('Details for incident ' + incidentNumber),
onClose: function(result) {
if (result === 'success') {
alert('Action confirmed for Incident ' + incidentNumber + '!');
} else {
alert('Action cancelled for Incident ' + incidentNumber + '.');
}
}
});
gdw.render();
}Updating the UI Page to Receive Data
Now, let’s modify the UI Page’s HTML to access and display these new parameters:
<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide:util">
<g:evaluate var="jvar_message" expression="RP.getWindowProperties().get('message')" />
<g:evaluate var="jvar_incident_sys_id" expression="RP.getWindowProperties().get('sysparm_id')" />
<g:evaluate var="jvar_incident_number" expression="RP.getWindowProperties().get('incident_number')" />
<div>
<h3>${jvar_message}</h3>
<p>This modal is associated with Incident: <strong>${jvar_incident_number}</strong></p>
<p>Incident Sys ID: <code>${jvar_incident_sys_id}</code></p>
<button class="btn btn-primary" onclick="closeModal('success', '${jvar_incident_number}')">Confirm</button>
<button class="btn btn-default" onclick="closeModal('cancel', '${jvar_incident_number}')">Cancel</button>
</div>
<script>
function closeModal(status, incidentNum) {
GlideModal.get().destroy({
result: status, // Pass back the status
incident: incidentNum // Pass back the incident number as well
});
}
</script>
</j:jelly>Key changes in the UI Page:
- We now use
RP.getWindowProperties().get('sysparm_id')andRP.getWindowProperties().get('incident_number')to retrieve the passed parameters. - The displayed message and incident details are dynamically updated.
- The
closeModalfunction now also passes back theincidentNumalong with the status in theresultobject. This demonstrates how you can return multiple pieces of data.
Key changes in the UI Action:
g_form.getUniqueValue()fetches the sys_id of the current record.g_form.getValue('number')fetches the value of the ‘number’ field.- These values are appended to the
contentURLassysparm_idandincident_number. Notice the use of&which is the XML-encoded equivalent of&required within Jelly. - The
onClosecallback now also receives the incident number passed back from the modal.
Retrieving Data from the Modal and Performing Actions
Often, you want to collect input from the user within the modal and then use that data on the parent form. This requires careful handling of the data passed back from the UI Page.
Let’s create a scenario where we want to ask the user for a reason for closure when closing an incident.
Step 1: Create a New UI Page for Closure Reason
Name: incident_closure_reason_modal
HTML:
<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide:util">
<g:evaluate var="jvar_incident_sys_id" expression="RP.getWindowProperties().get('sysparm_id')" />
<g:evaluate var="jvar_incident_number" expression="RP.getWindowProperties().get('incident_number')" />
<div class="container">
<h3>Provide Closure Reason for ${jvar_incident_number}</h3>
<div class="form-group">
<label for="closure_reason">Reason for Closure:</label>
<textarea id="closure_reason" class="form-control" rows="4"></textarea>
</div>
<div class="modal-footer">
<button class="btn btn-primary" onclick="submitClosureReason()">Submit</button>
<button class="btn btn-default" onclick="GlideModal.get().destroy()">Cancel</button>
</div>
</div>
<script>
function submitClosureReason() {
var reason = gel('closure_reason').value;
if (reason.trim() === '') {
alert('Please enter a closure reason.');
return;
}
// Pass back the reason and incident sys_id
GlideModal.get().destroy({
result: 'closed',
reason: reason,
incident_sys_id: '${jvar_incident_sys_id}'
});
}
</script>
</j:jelly>Explanation:
- We have a
textareafor the user to enter their reason. - The
submitClosureReasonfunction retrieves the value, performs a basic validation, and then usesGlideModal.get().destroy()to close the modal, passing back an object containing the status (‘closed’), the reason, and the incident sys_id.
Step 2: Create a UI Action to Trigger the Closure Reason Modal
Name: Close Incident with Reason
Table: Incident [incident]
Action name: close_incident_reason
Form button: Check this box.
Client: Check this box.
Onclick: openClosureReasonModal();
Script:
function openClosureReasonModal() {
var incidentSysId = g_form.getUniqueValue();
var incidentNumber = g_form.getValue('number');
var gdw = new GlideModal({
title: 'Closure Reason',
contentURL: 'incident_closure_reason_modal.do?sysparm_id=' + incidentSysId + '&incident_number=' + encodeURIComponent(incidentNumber),
onClose: function(result) {
// Check if the modal was submitted and not just closed
if (result && result.result === 'closed') {
var closureReason = result.reason;
var incidentID = result.incident_sys_id;
// Now, update the incident record
var gr = new GlideRecord('incident');
if (gr.get(incidentID)) {
gr.state = 7; // Assuming state 7 is 'Closed'
gr.close_notes = closureReason;
gr.update();
g_form.addInfoMessage('Incident ' + gr.number + ' has been closed with the reason: ' + closureReason);
// Reload the form to reflect changes
g_form.reloadPage();
} else {
g_form.addErrorMessage('Failed to retrieve incident record for closure.');
}
} else {
g_form.addInfoMessage('Incident closure cancelled.');
}
}
});
gdw.render();
}Explanation:
- The UI Action opens the
incident_closure_reason_modal.doUI Page, passing the incident’s sys_id and number. - The
onClosefunction is where the magic happens:- It checks if
resultexists and ifresult.resultis ‘closed’. This distinguishes between a user closing the modal without submitting and a successful submission. - It extracts the
reasonandincident_sys_idfrom the returned object. - It creates a
GlideRecordfor the ‘incident’ table. - It uses
gr.get(incidentID)to fetch the specific incident record. - It sets the
stateto ‘Closed’ (assuming ‘7’ is the correct sys_id for your Closed state) and populates theclose_notesfield with the provided reason. gr.update()saves the changes to the database.- An informational message is displayed, and
g_form.reloadPage()refreshes the form to show the updated state and fields.
- It checks if
This example showcases how to collect data from a modal, process it, and update the underlying ServiceNow record, making GlideModal a powerful tool for custom business processes.
Advanced Considerations and Best Practices
- Error Handling: Always include robust error handling in both your UI Page and the calling script. What happens if the UI Page fails to load? What if the data retrieval or update fails?
- Security: Ensure your UI Pages and the data they access are secured appropriately using ACLs and ServiceNow’s security framework. Avoid passing sensitive information directly in URL parameters if possible.
- Performance: For complex UI Pages, consider their loading time. Large amounts of client-side JavaScript or inefficient Jelly can impact performance.
- Responsiveness: Design your UI Pages to be responsive, especially if they will be accessed on different devices.
- GlideModalAPI vs. GlideDialogWindow: While
GlideDialogWindowwas the older API,GlideModalis the modern, preferred API. UseGlideModalfor new development. It offers better styling and a more consistent user experience. - Using `g:set` for Variables: Within Jelly, use
<g:set var="myVar" value="${someValue}" />to declare variables that can be accessed within the Jelly script. - Passing Complex Data: For passing more complex data structures, consider stringifying JSON objects and passing them as URL parameters, then parsing them back in the UI Page.
Troubleshooting Common GlideModal Issues
Even with careful planning, you might encounter issues. Here are some common problems and how to address them:
1. Modal Doesn’t Appear or Shows an Error
- Check the Console: Open your browser’s developer console (usually by pressing F12). Look for JavaScript errors. Errors in your client script or the UI Page’s script will be reported here.
- Verify
contentURL: Double-check that the UI Page name in thecontentURLis spelled correctly and exists. Ensure there are no typos in the URL parameters. - Client-Side Scripting: Make sure the UI Action is marked as “Client” and has a function assigned to “Onclick”.
- UI Page Rendering: In your UI Page, ensure the Jelly is well-formed and that the embedded JavaScript is syntactically correct.
- ACLs: Verify that the user has read access to the UI Page itself.
2. Data Not Being Passed Correctly to the UI Page
- URL Encoding: Always use
encodeURIComponent()for any variable data you pass in the URL to prevent issues with special characters. - Parameter Names: Ensure the parameter names used in the
contentURLexactly match the names you are trying to retrieve usingRP.getWindowProperties().get('parameter_name')in the UI Page. - `sysparm_` Prefix: Standard ServiceNow URL parameters often start with
sysparm_. While you can use other names, be aware of common conventions.
3. Data Not Being Returned Correctly from the UI Page
- `onClose` Callback: Ensure your
onClosefunction is correctly defined in the GlideModal call. - `GlideModal.get().destroy()`: Verify that you are calling
GlideModal.get().destroy()within your UI Page’s script and that you are passing the correct object/value for the `result` parameter. - Object vs. Primitive: Remember that
resultin theonClosecallback can be a primitive value (like a string or boolean) or an object, depending on what you pass todestroy(). Check the type in your callback.
4. Styling Issues in the Modal
- Global CSS vs. Local CSS: UI Pages inherit global styles, but you can override them with your own CSS within the UI Page’s HTML or by linking to a UI Script. Be mindful of Bootstrap classes, as ServiceNow relies heavily on it.
- Scoped CSS: If you’re using scoped applications, ensure your CSS is correctly scoped.
Interview Relevance: Why GlideModal is Important
For any ServiceNow interview, especially for development or advanced administration roles, understanding GlideModal is a significant advantage. Interviewers often probe for practical application and problem-solving skills. Here’s why it’s frequently asked about:
- Core Skill Demonstration: It shows you can go beyond basic form customization and build more interactive user experiences.
- Understanding Client-Side Scripting: Effectively using GlideModal requires a solid grasp of client-side JavaScript, Jelly, and ServiceNow’s client-side APIs.
- Problem Solving: Questions might involve scenarios like: “How would you create a popup to collect additional information before closing a change request?” or “Describe a situation where you used a modal to improve user workflow.”
- API Knowledge: Being able to discuss
GlideModal.open(),GlideModal.get().destroy(), and how to pass parameters is essential. - UI Page Design: It demonstrates an understanding of how to build modular UI components.
- Best Practices: Discussing performance, security, and error handling related to GlideModal shows a mature approach to development.
Example Interview Question: “Can you explain how you would use GlideModal to display a confirmation dialog before a user submits a critical record update, and how you would retrieve the user’s confirmation status?”
Answer Strategy: Mention creating a simple UI Page with “Yes” and “No” buttons. Explain how to call it using GlideModal.open(), passing a `contentURL` to the UI Page. Crucially, describe the `onClose` callback function in the UI Action and how it receives the ‘Yes’ or ‘No’ status passed back from the UI Page’s `GlideModal.get().destroy()` method, and then conditionally proceed with the record update.
Conclusion
GlideModal is an indispensable tool in the ServiceNow developer’s arsenal. By mastering the art of calling UI Pages with GlideModal, you can significantly enhance user experience, streamline complex processes, and build more dynamic and responsive applications. Whether you’re developing custom solutions, automating workflows, or simply looking to impress in your next interview, a deep understanding of GlideModal will undoubtedly set you apart.
Remember to practice, experiment with different scenarios, and always refer to the official ServiceNow documentation for the most up-to-date information and advanced features. Happy coding!