Understanding ServiceNow Client Scripts: A Comprehensive Guide

Unlocking Dynamic Experiences: A Deep Dive into ServiceNow Client Scripts

Ever wondered how those fancy, interactive elements on your ServiceNow forms come to life? How a field instantly becomes mandatory when you select a certain option, or how a message pops up to guide you through a process? Chances are, you’re looking at the magic of Client Scripts.

In the world of ServiceNow, Client Scripts are your go-to tool for bringing forms, lists, and user interfaces to life directly in the user’s browser. They’re like the unsung heroes working behind the scenes, ensuring a smooth, responsive, and intuitive experience for everyone, whether they’re navigating through UI15, UI16, or the shiny new Next Experience interface (Q11).

This article will take you on a journey through the ins and outs of Client Scripts, exploring their types, the powerful APIs they leverage, and how they interact with other client-side logic. We’ll even sprinkle in some best practices, common troubleshooting tips, and insights perfect for acing your next ServiceNow interview.

What Exactly Are Client Scripts?

At its core, a Client Script in ServiceNow is a piece of JavaScript code that executes on the client side – meaning, right there in your web browser. Unlike server-side scripts (like Business Rules or Script Includes) which run on the ServiceNow server, Client Scripts don’t need to communicate back and forth with the server for every little interaction. This makes them incredibly fast and efficient for enhancing the user experience directly on a form or list.

Think of it this way: when you’re filling out a paper form, you might instantly see a note that says “if you check this box, you must fill out section B.” Client Scripts do that, but digitally and dynamically. They react to user actions and form loads to make fields mandatory, show/hide information, validate input, and so much more.

The Four Pillars: Types of Client Scripts (Q72)

ServiceNow offers four distinct types of Client Scripts, each designed for specific moments in a user’s interaction with a form or list:

  1. OnLoad: As the name suggests, an OnLoad script runs every single time a form loads. It’s perfect for initial setup, like setting default values, hiding fields based on the user’s role, or displaying an initial message.
  2. OnChange: This script type springs into action when the value of a specific field changes. It’s incredibly useful for creating dynamic forms, where a change in one field affects others – for example, making a “Reason for Change” field mandatory only when the “Status” is set to “Canceled.”
  3. OnSubmit: Before a form is officially submitted (e.g., when you click “Save” or “Update”), an OnSubmit script gets its chance to run. This is your last line of defense for data validation, ensuring all necessary information is provided and formatted correctly before it hits the database.
  4. OnCellEdit: This is a less common but powerful client script, specifically designed for list views. It runs when you edit a value directly within a cell on a list and then try to save it. It’s ideal for validating bulk edits or applying business logic directly within a list interface.

Deep Dive: Exploring Each Client Script Type

OnLoad Client Scripts: The Form’s First Impression

When a form first appears on your screen, an OnLoad script is the first piece of client-side logic to execute. This makes it ideal for:

  • Setting initial field visibility or read-only states.
  • Populating default values.
  • Displaying informational messages.
  • Making dynamic adjustments based on the current logged-in user (e.g., g_user.userID to get the current user’s system ID (Q13)).

OnChange Client Scripts: Reacting to User Input

OnChange scripts are all about interactivity. They run whenever a specified field’s value changes, and interestingly, they also execute once when the form initially loads, just like an OnLoad script. This dual execution can be helpful but also requires careful consideration.

OnChange Parameters: What Do They Tell You? (Q74)

When you write an OnChange script, ServiceNow provides you with several useful parameters:

  • control: This is a reference to the actual HTML element of the field that was changed. While it gives you direct access, it’s generally best practice to use g_form methods instead of direct DOM manipulation for future compatibility and stability.
  • oldValue: The value of the field *before* the change occurred.
  • newValue: The value of the field *after* the change occurred.
  • isLoading: A Boolean (true/false) indicating if the form is currently loading. This is crucial for distinguishing between an actual user change and the initial form load.
  • isTemplate: A Boolean indicating if the value is being set by a template rather than manual input.

Troubleshooting Tip: Making OnChange Work Only on Change (Q75)

Because OnChange scripts run on load, you often need to add a condition to prevent your logic from firing prematurely. A common pattern is:

function onChange(control, oldValue, newValue, isLoading, isTemplate) {
    if (isLoading || newValue === '') {
        return; // Don't run the script on form load or if the new value is empty
    }
    // Your actual logic here, for when the field value truly changes
    // ...
}

If, for some reason, you *want* your OnChange logic to execute on load without checking isLoading, you simply remove that condition. But be mindful: this is less common and usually an OnLoad script is more appropriate for initial setup.

OnSubmit Client Scripts: The Final Gatekeeper

OnSubmit scripts run just before the form data is sent to the server. This is where you perform any last-minute validations to ensure data integrity. If your OnSubmit script finds an issue, you can stop the submission and prompt the user to correct it.

Stopping Form Submission (Q76)

To prevent a form from being submitted, your OnSubmit client script simply needs to return false:

function onSubmit() {
    var shortDescription = g_form.getValue('short_description');
    if (shortDescription === '') {
        g_form.addErrorMessage('Short Description cannot be empty!');
        return false; // This stops the form submission
    }
    // If all checks pass, the form will submit normally
    return true;
}

This is a client-side way to prevent submission. Remember, on the server side, you’d use current.setAbortAction(true) within a Before Business Rule to achieve a similar effect (Q157). It’s crucial to understand both for a robust application!

OnCellEdit Client Scripts: List View Dynamics

OnCellEdit scripts operate on list views. When a user double-clicks a cell to edit its value directly in a list and then saves it, this script runs. It’s particularly useful for validating data entered in bulk or applying business logic immediately after a list edit.

OnCellEdit Parameters (Q78)

These scripts receive five parameters:

  • sysIDs: An array of the sys_ids of the records being edited.
  • table: The name of the table being edited.
  • oldValues: An array of the original values for the edited cells.
  • newValues: An array of the new values entered for the edited cells.
  • callback: A function that you must call to either allow or prevent the cell edit.

The Power Tools: Essential Client-Side APIs

Client Scripts wouldn’t be half as powerful without the rich set of client-side APIs that ServiceNow provides. These APIs allow you to interact with the form, the current user, and even communicate with the server.

Some of the most frequently used client-side APIs include GlideUser, GlideForm, GlideAjax, GlideModal, GlideNavigation, and g_scratchpad (Q129).

g_user: Knowing Your User (GlideUser API) (Q68)

The g_user object (GlideUser API) is your window into the current logged-in user’s information and their roles on the client side. It’s incredibly useful for tailoring form behavior based on who is interacting with it.

Key g_user Methods (Q69)

  • g_user.firstName: Retrieves the user’s first name.
  • g_user.lastName: Retrieves the user’s last name.
  • g_user.getFullName(): Retrieves the user’s full name.
  • g_user.userName: Retrieves the user’s login name.
  • g_user.userID: Retrieves the sys_id of the current logged-in user. (Q13)
  • g_user.hasRole('itil'): Checks if the current user has a specific role.

g_form: Master of the Form (GlideForm API) (Q70)

The g_form object (GlideForm API) is your primary interface for making modifications to the form itself. It provides a robust set of methods to control fields, sections, messages, and even attachments.

Common g_form Methods (Q71)

  • g_form.addInfoMessage("Your message here");: Displays a blue informational message at the top of the form.
  • g_form.addErrorMessage("An error occurred!");: Displays a red error message.
  • g_form.setMandatory("field_name", true/false);: Makes a field mandatory or optional.
  • g_form.setReadOnly("field_name", true/false);: Makes a field read-only or editable.
  • g_form.setVisible("field_name", true/false);: Hides or shows a field.
  • g_form.setDisplay("field_name", true/false);: Hides or shows a field, also collapsing its allocated space on the form.
  • g_form.getValue("field_name");: Gets the backend value (sys_id for references, choice value for choices) of a field (Q221).
  • g_form.getDisplayValue("field_name");: Gets the display value (e.g., name for references, label for choices) of a field (Q221).
  • g_form.addOption("field_name", "value", "label");: Adds an option to a choice list or select box.
  • g_form.enableAttachments();: Enables or disables the attachment functionality for the current form.
  • g_form.getSectionNames();: Returns an array of all section names on the form (Q107, Q110).
  • g_form.setSectionDisplay("section_name", true/false);: Hides or shows an entire section (Q107, Q110).
  • g_form.getEditableFields();: Returns an array of all currently editable field names (Q108).
  • g_form.hideRelatedLists();: Hides all related lists on the form (Q109).

setVisible vs. setDisplay: A Nuance You Should Know (Q106)

This is a classic interview question! While both methods hide a field, they do so differently:

  • g_form.setVisible("field_name", false);: Hides the field but leaves its allocated space on the form. This can sometimes result in awkward gaps.
  • g_form.setDisplay("field_name", false);: Hides the field AND removes its allocated space, making the form elements reflow naturally. This is generally preferred when you want to truly remove a field from view without visual disruption.

Making Fields Mandatory/Read-Only: Multiple Ways (Q42)

It’s important to know that you can control field states (mandatory, read-only) in several ways, and Client Scripts (using g_form.setMandatory and g_form.setReadOnly) are just one. Others include:

  • Dictionary Properties: Directly on the field’s dictionary entry (server-side, always applies).
  • Dictionary Overrides: For extending tables, to override dictionary properties for specific tables.
  • UI Policies: Client-side logic for dynamic changes based on conditions.
  • Data Policies: Server-side (and optionally client-side) logic for enforcing data integrity, regardless of how the data is entered.

g_navigation: Guiding the User (GlideNavigation API) (Q87)

The g_navigation object allows you to programmatically navigate users to different URLs or records from the client side. For example, you might use it to open a related record in a new tab after a user action.

g_list: Dynamic List Filters (Q205)

While less common on standard forms, g_list can be used to dynamically adjust filters on list collector variables (like the “Watch list” field). This allows you to restrict the available choices in a list collector based on other fields on the form.

g_scratchpad: Bridging Server and Client (Q169, Q261, Q264)

The g_scratchpad is a unique object specifically used with Display Business Rules. A Display Business Rule runs on the server before a record is displayed to the user. Its primary purpose is to collect server-side data that isn’t typically part of the record itself and pass it to the client for use in Client Scripts or UI Policies. This avoids unnecessary GlideAjax calls (more on that later!).

For example, you could check the current user’s department on the server using a Display BR and store it in g_scratchpad.userDepartment. Then, your OnLoad client script can access g_scratchpad.userDepartment and dynamically set a field value or hide a section based on that information.

Client-Side Orchestration: UI Policies vs. Client Scripts

It’s common for newcomers to get UI Policies and Client Scripts mixed up, as both can perform similar actions (making fields mandatory, visible, or read-only) on the client side. However, they have distinct use cases and an important execution order.

UI Policies: Low-Code Form Control (Q58)

UI Policies are a low-code/no-code way to dynamically change the behavior of form fields based on conditions. You define conditions and then specify actions, such as:

  • Making fields mandatory.
  • Making fields read-only.
  • Hiding or showing fields.
  • Showing or hiding related lists at certain conditions.

They are generally preferred over Client Scripts for these simple, conditional UI changes because they are easier to maintain and require less coding expertise.

Key UI Policy Features:

  • Global Check Box (Q59): When checked, the UI Policy applies to all form views. Uncheck it, and you’ll specify a particular view for the policy to apply to.
  • Reverse if False (Q60): If selected, the actions defined by the UI Policy are automatically reversed when the condition is no longer met. For instance, if a field became mandatory when a condition was true, it becomes optional again when the condition is false. This saves you from writing reverse logic.
  • On Load Check Box (Q61): If checked, the UI Policy’s conditions and actions are evaluated and applied immediately when the form loads. If unchecked, the policy only triggers when a field or condition changes on the form *after* it has loaded.
  • Inherit Check Box (Q62): When checked, the UI Policy will also apply to any child tables that extend the table on which the policy is defined.
  • Run scripts (Q63): Yes, you can write JavaScript in UI Policies! By checking the “Run scripts” box, you get a script editor for “Execute if true” and “Execute if false.” This allows for more complex logic that can’t be achieved with simple UI Policy actions. However, if your logic becomes too complex, a Client Script might be a cleaner approach.

UI Policies vs. Data Policies (Q67)

Another common comparison is between UI Policies and Data Policies:

  • Client-side vs. Both: UI Policies work exclusively on the client side. Data Policies work on both client and server sides, enforcing data integrity regardless of how data is entered (form, import, web service).
  • Hiding Fields: You *cannot* hide a field using a Data Policy. Data Policies focus on mandatory/read-only states.
  • Scripting: You *cannot* write scripts directly within a Data Policy.
  • Views: UI Policies can be applied to specific views. Data Policies apply globally.
  • Sources: UI Policies only work on forms. Data Policies work on all data entry sources.

Therefore, you cannot convert a UI Policy to a Data Policy if the UI Policy is controlling data visibility, views, related lists, or custom scripts (Q65, Q270).

The Grand Unveiling: Script Execution Order (Q73, Q263)

Understanding the order in which scripts run is critical for predicting behavior and troubleshooting. Here’s a simplified (but still comprehensive) order of execution for client-side and related server-side scripts when a form is loaded or submitted:

  1. Query Business Rules
  2. Display Business Rules (server-side, populate g_scratchpad)
  3. OnLoad Client Scripts
  4. OnLoad UI Policies
  5. OnChange Client Scripts (when a field value changes)
  6. OnChange UI Policies (when a field value changes)
  7. OnSubmit Client Scripts (before form submission)
  8. Client-Side UI Actions
  9. Server-Side UI Actions (triggered after client-side, if any)
  10. Before Business Rules
  11. Database Operation (insert, update, delete)
  12. After Business Rules
  13. Email Notifications, Workflows, etc.

Crucially, Client Scripts run before UI Policies when a form loads or a field changes. This means a Client Script might make a field read-only, but a later UI Policy (with conflicting logic) could override that. Plan your logic accordingly!

Advanced Client-Side Interactions

GlideAjax: Talking to the Server from the Client (Q81)

Sometimes, your client-side script needs information or to perform an action that only the server can provide or handle (e.g., querying a database for complex data, calling a custom utility). This is where GlideAjax comes in. It’s a client-side API used to make asynchronous calls to a Script Include on the server, allowing your client script to get data or execute server-side logic without reloading the entire form.

This is one of the four main ways to get values from the server to the client, along with GlideRecord (use sparingly in client scripts!), g_form.getReference (also use sparingly!), and g_scratchpad (Q88).

Asynchronous vs. Synchronous GlideAjax (Q84, Q85)

Understanding the difference is key, especially for user experience and interviews:

  • Asynchronous GlideAjax (`getXMLAnswer`): This is the preferred method. It sends a request to the server and continues executing the rest of your client script *without waiting* for a response. When the server responds, a specified callbackFunction handles the result. This keeps the user interface responsive.
  • Synchronous GlideAjax (`getXMLWait`): This method sends a request and *waits* for the server’s response before executing any further client script code. While sometimes necessary (e.g., if a subsequent action absolutely depends on the server’s immediate response (Q86)), it can make the UI unresponsive if the server takes time to reply. Use it sparingly!

GlideAjax Syntax Example (Asynchronous) (Q82)

var ga = new GlideAjax('YourScriptInclude'); // Name of your server-side Script Include
ga.addParam('sysparm_name', 'yourFunction'); // Function within the Script Include to call (Q163)
ga.addParam('sysparm_caller', g_form.getValue('u_caller')); // Pass client-side data to the server
ga.getXMLAnswer(callbackFunction); // Specify the callback function

function callbackFunction(response) {
    var answer = response; // The data returned from the server
    // Process the response here
    g_form.setValue('short_description', answer);
}

Remember that functions in your Script Include starting with an underscore (_) are considered private and cannot be called directly from the client (Q164).

UI Actions: Client-Side and Server-Side Capabilities (Q79)

UI Actions (buttons, context menu items) are server-side by default. However, by checking the “Client” checkbox, you can make them execute client-side JavaScript. This is useful for performing client-side validations or popping up confirmation messages before any server-side logic kicks in.

Moving from Client to Server in UI Actions (Q80, Q165)

A powerful technique in hybrid UI Actions (client-side script with server-side logic) is to use gsftSubmit(). After your client-side validation is complete, you can call gsftSubmit(null, g_form.getFormElement(), 'action_name'); to re-trigger the UI Action, but this time, it will bypass the client script and execute only the server-side code (the UI Action’s “Script” field).

UI Pages: Custom Web Experiences (Q89)

UI Pages are like miniature web pages within ServiceNow, built using HTML, CSS, and Jelly scripting. They allow you to create highly customized interfaces that go beyond standard form elements.

Calling UI Pages from Client Scripts/UI Actions (Q90, Q91, Q124, Q225)

You can launch UI Pages from Client Scripts or UI Actions using the GlideModal or GlideDialogWindow APIs:

var gdw = new GlideModal('ui_page_name'); // Or GlideDialogWindow
gdw.setTitle('My Custom Popup');
gdw.setSize(600, 400); // Set dimensions
gdw.setPreference('recordSysId', g_form.getUniqueValue()); // Pass values (Q92, Q226)
gdw.render(); // Open the modal

To access values passed via setPreference within the UI Page’s Jelly script, you use RP.getWindowProperties().get('keyName') (Q93, Q227). To access HTML elements within the UI Page from its client script, use gel(), which is similar to document.getElementById() (Q229).

And to close a UI Page programmatically, simply use GlideDialogWindow.get().destroy(); (Q95, Q228).

UI Macros: Custom Form Controls (Q96)

UI Macros are smaller, reusable pieces of Jelly code primarily used to create custom form controls (like unique buttons or visual elements) or to extend existing ones. They are often called via UI Formatters or directly from the dictionary.

Calling UI Macros on Forms and Dictionary: (Q97, Q98)

  • On a Form: Add a UI Formatter to the form, which then references the UI Macro (e.g., macro_name.xml).
  • On the Dictionary: Add an attribute to a field’s dictionary entry: ref_contributions=macro_name. This will display the UI Macro next to the field.

Hiding UI Macros with Script (Q99)

To hide or show a UI Macro dynamically, you generally need to use direct JavaScript DOM manipulation, but this requires the “Isolate script” checkbox (discussed next) to be unchecked:

document.getElementById('uimacro_id').style.display = 'none'; // Hide
document.getElementById('uimacro_id').style.display = 'block'; // Show

Yes, you can even call UI Pages from within a UI Macro (Q100) by embedding a client script that uses GlideModal or GlideDialogWindow, just like a regular Client Script.

GlideModalForm: Calling Table Forms Directly (Q125, Q231)

Similar to GlideModal for UI Pages, GlideModalForm allows you to open a standard ServiceNow form (e.g., an Incident record) within a modal window directly from client-side scripts like UI Actions or Client Scripts.

Client Script Best Practices and Troubleshooting

The Isolate script Checkbox (Q101)

This checkbox on Client Scripts is a significant setting. When checked (which is the default and recommended), the script runs in its own isolated environment. This prevents conflicts with other scripts and ensures predictable behavior. However, it also means your script cannot directly access or manipulate the HTML Document Object Model (DOM) of the page (like document.getElementById). For direct DOM manipulation (e.g., hiding a UI Macro by ID), you would need to uncheck this box, which is generally discouraged unless absolutely necessary and you understand the risks.

General Best Practices (Q102)

Adhering to best practices ensures your Client Scripts are performant, maintainable, and reliable:

  • Enclose Code in Functions: Always wrap your script logic within the provided functions (onLoad, onChange, etc.) and avoid global variables unless absolutely necessary.
  • Avoid DOM Manipulation: Whenever possible, use the g_form object (e.g., g_form.setValue, g_form.setMandatory) instead of directly manipulating HTML elements. This makes your scripts more resilient to future UI changes in ServiceNow.
  • Avoid g_form.getReference for Large Datasets: While g_form.getReference('field_name').field_value; works to retrieve values from a referenced record, it performs a synchronous call to the server and can be slow if used frequently or on large datasets. Prefer GlideAjax for retrieving server-side data, especially if you need multiple fields or complex queries.
  • Use Asynchronous Calls: Always prefer asynchronous GlideAjax (getXMLAnswer) over synchronous (getXMLWait) to prevent blocking the UI and ensure a smooth user experience.
  • Minimize Alerts: alert() statements can be disruptive. Use g_form.addInfoMessage() or g_form.addErrorMessage() for user feedback on forms.
  • Use UI Policies for Simple UI Control: If a field simply needs to be mandatory, read-only, or visible based on a condition, use a UI Policy before resorting to a Client Script.
  • Validate on Both Client and Server: Implement validation on the client side for immediate user feedback (Client Scripts, UI Policies) and on the server side (Business Rules, Data Policies) for robust data integrity.

Client Scripts in the Service Catalog

The Service Catalog introduces its own flavor of client-side scripting, applied to catalog items, variables, and variable sets.

Variables and Variable Sets (Q282, Q283, Q284)

In catalog items, “variables” are essentially the fields users fill out. “Variable Sets” are reusable groups of variables. They save development time and ensure consistency across multiple catalog items. Instead of recreating the same set of questions for 20 different items, you create a variable set once and attach it. Any changes to the variable set reflect across all linked items.

  • Single-Row Variable Set (Q285): Used for capturing data for a single entity, like contact information.
  • Multi-Row Variable Set (Q285): Presents variables in a grid layout, allowing users to add multiple rows of data, like requesting multiple software licenses.

Reading Multi-Row Variable Set Values (Q286)

Accessing values from a Multi-Row Variable Set requires parsing a JSON string:

var mrvsRows = g_form.getValue("mrvs_internal_name"); // Returns a JSON string
var oMrvs = JSON.parse(mrvsRows);
var totalCost = 0;
for(var i in oMrvs) {
    totalCost += parseFloat(oMrvs[i]["cost_variable_internal_name"]);
}
g_form.setValue("total_cost_variable", totalCost);

Catalog UI Policies vs. Normal UI Policies (Q288)

Catalog UI Policies are specifically designed for the Service Catalog. The main differences are:

  • They do not control form views (as catalog items usually don’t have multiple views in the same way regular forms do).
  • They apply to the catalog item form itself, the requested item (RITM) form, and catalog tasks (SCTASK).

Catalog Client Scripts vs. Normal Client Scripts (Q289)

Similar distinctions apply to Catalog Client Scripts:

  • Types: Catalog Client Scripts typically have 3 types (OnLoad, OnChange, OnSubmit), lacking OnCellEdit as it’s not applicable to catalog items.
  • Applicability: They work on Catalog Items, Requested Items, and Catalog Tasks.
  • Views: Unlike normal Client Scripts, Catalog Client Scripts generally do not work on specific views.

Execution Order in Catalog (Q287)

When you have scripts on both the catalog item and its associated variable sets:

  • Catalog Item Client Scripts run first, then Variable Set Catalog Client Scripts.
  • Catalog Item UI Policies run first, then Variable Set Catalog UI Policies.

Specific Catalog Use Cases:

  • UI Policy on Record Producer Only (Q290): To make a Catalog UI Policy work only on a Record Producer, check the “Applies on target Record” checkbox.
  • UI Policy on Catalog Tasks Only (Q291): To make a Catalog UI Policy work only on Catalog Tasks, check the “Applies on Catalog Task” checkbox.

Record Producer Scripts and Client APIs (Q308)

It’s important to remember that the “Script” field in a Record Producer executes on the server side (it generates the target record). Therefore, you cannot use client-side APIs (like g_form or GlideAjax) directly within a Record Producer’s server-side script.

Conclusion

Client Scripts are an indispensable part of building engaging and efficient user experiences in ServiceNow. By mastering their types, leveraging the robust client-side APIs, and understanding their interactions with UI Policies and other client-side tools, you can transform static forms into dynamic, intelligent interfaces that guide users seamlessly through their tasks.

Always remember the best practices: prioritize UI Policies for simple changes, use g_form over direct DOM manipulation, and embrace asynchronous GlideAjax for server communication. With these tools and a thoughtful approach, you’ll be creating delightful ServiceNow experiences in no time!

Scroll to Top