Mastering GlideForm: Essential Methods for ServiceNow Client-Side Scripting
In the dynamic world of ServiceNow development, crafting intuitive and efficient user experiences is paramount. A core component of this is understanding and leveraging the power of client-side scripting, and at its heart lies the GlideForm API. This API, often accessed via the g_form object, is your gateway to manipulating forms in real-time, responding to user interactions, and ensuring data integrity before it even hits the server. Mastering these methods is not just about writing code; it’s about building smarter, more responsive applications.
This article will dive deep into some of the most crucial GlideForm methods, providing practical explanations, real-world examples, and insights into how they can elevate your ServiceNow development. We’ll also touch upon their server-side counterparts where relevant, offer troubleshooting tips, and highlight their importance in technical interviews.
Understanding the GlideForm Object (g_form)
Before we explore specific methods, it’s essential to grasp what the g_form object represents. When a ServiceNow form loads in your browser, the g_form object is automatically available in the client-side JavaScript environment. It acts as an interface to the current form, allowing you to interact with its fields, sections, and other elements. Think of it as the “controller” for your form, enabling dynamic behavior based on user actions or predefined logic.
It’s important to distinguish g_form from its server-side sibling, the current object. While both deal with form data, their execution contexts are fundamentally different:
g_form(Client-Side): Executes in the user’s browser. It’s perfect for immediate feedback, UI enhancements, validation, and controlling field visibility or mandatory status *before* data is submitted to the server.current(Server-Side): Executes on the ServiceNow instance’s server. This object is used in Business Rules, Script Includes (when called from server-side scripts), and other server-side logic to read, modify, and save record data.
Core GlideForm Methods for Dynamic Forms
Let’s explore some of the most impactful methods available through the g_form object that will significantly enhance your client-side scripting capabilities.
1. Getting and Setting Field Values: The Foundation of Interaction
The ability to read and write data to form fields is the most fundamental aspect of client-side scripting. Whether you need to populate a field based on another, clear a value, or set a default, these methods are your go-to.
g_form.getValue(fieldName)
This method retrieves the current value of a specified field on the form. It returns the value in its raw format. For reference fields, it typically returns the sys_id.
Example: Populating a ‘Description’ based on ‘Short Description’
Imagine you want to automatically populate the ‘Description’ field with the value of the ‘Short Description’ field when the latter is changed. This is a common requirement for Incident or Request items.
You would typically implement this in an onChange client script on the ‘Short Description’ field:
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading || newValue === '') {
return;
}
// Get the value from the 'short_description' field
var shortDescValue = g_form.getValue('short_description');
// Set the value for the 'description' field
g_form.setValue('description', shortDescValue);
}
Key Takeaway: getValue() is essential for reading data to use in further logic or to populate other fields.
g_form.setValue(fieldName, value, displayValue)
This is the workhorse for setting field values. It accepts the field name and the value you want to set. For reference fields, you usually provide the sys_id of the referenced record as the value. An optional third parameter, displayValue, can be used to set the displayed text for reference fields, which is particularly useful when you only have the display name and not the sys_id.
Example: Setting a Reference Field and its Display Value
Let’s say you have a ‘Configuration Item’ (cmdb_ci) reference field and you want to set it based on a value retrieved from another field or a server call. You might also want to ensure the correct display name is shown.
function setConfigurationItem(ciSysId, ciDisplayName) {
// Set the value (sys_id) for the 'cmdb_ci' field
g_form.setValue('cmdb_ci', ciSysId);
// Optionally, set the display value. This is often done automatically when setting the sys_id,
// but explicit setting can be useful in complex scenarios or when you might not have the sys_id readily available.
// For reference fields, the third parameter is the display value.
g_form.setValue('cmdb_ci', ciSysId, ciDisplayName);
}
// Example usage (e.g., called from another script or event)
// Assuming you have the sys_id and display name from somewhere
// setConfigurationItem('a7e21b63db1234567890abcd12345678', 'My Server 01');
Important Note on setValue for Reference Fields: When setting a reference field using setValue(), the primary way is to pass the sys_id as the second argument. The third argument is for explicitly setting the display value, which is less commonly needed if the system can resolve it.
Server-Side Comparison: On the server-side, the current object is used. The equivalent of g_form.setValue() is current.field_name.setValue(value);. For reference fields, you’d set the sys_id.
// Server-side example
current.short_description.setValue("This is a critical incident.");
current.assigned_to.setValue("6816f79cc0a8016401c5a33be04be441"); // Setting sys_id for a reference field
g_form.setDisplayValue(fieldName, displayValue)
This method is specifically useful for setting the displayed value of a field, particularly reference fields, without necessarily needing the sys_id. The system will attempt to find a matching record based on the provided display value. This is often used when you have a user-friendly name rather than a system identifier.
Example: Setting a User Field by Name
Suppose you want to set the ‘Assigned To’ field to a specific user by their name. While setting by sys_id is generally preferred for accuracy, this method can be helpful.
// This is less common and might not always work reliably if names are not unique or have special characters.
// It's generally better to use sys_id if possible.
// g_form.setDisplayValue('assigned_to', 'Abel Tuter');
Real-world scenario: You might receive a user’s name from an external system and want to map it to a user record. setDisplayValue can attempt this mapping.
Caution: Using setDisplayValue for reference fields relies on the system’s ability to resolve the display value to a unique record. If multiple records share the same display value, the behavior can be unpredictable. Always prefer setting by sys_id when possible.
g_form.clearValue(fieldName)
As the name suggests, this method clears the value of a specified field. This is useful for resetting fields or removing data when certain conditions are met.
Example: Clearing a Field Based on a Choice
If a user selects “Other” in a choice list, you might want to make a corresponding “Other Specify” text field visible and clear its previous value.
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading || newValue === '') {
return;
}
if (newValue === 'other') {
g_form.setVisible('other_specify_field', true);
g_form.clearValue('other_specify_field'); // Clear any previous entry
g_form.setMandatory('other_specify_field', true);
} else {
g_form.setVisible('other_specify_field', false);
g_form.clearValue('other_specify_field'); // Clear it when not visible
g_form.setMandatory('other_specify_field', false);
}
}
2. Controlling Field Visibility and Read-Only Status
Dynamic forms often require fields to appear or disappear, or to be editable or read-only, based on the state of the record or user actions. GlideForm provides powerful methods for this.
g_form.setVisible(fieldName, isVisible)
This method controls whether a field is visible on the form. isVisible should be true to show the field and false to hide it.
Example: Showing a Field Only for Specific Record Types
On an incident form, you might want to show a ‘SLA Due Date’ field only if the ‘Impact’ is ‘High’.
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading || newValue === '') {
return;
}
var impact = g_form.getValue('impact');
if (impact === '1') { // Assuming '1' is the value for High Impact
g_form.setVisible('u_sla_due_date', true);
} else {
g_form.setVisible('u_sla_due_date', false);
}
}
g_form.setReadOnly(fieldName, isReadOnly)
This method makes a field read-only. Set isReadOnly to true to make it read-only, and false to make it editable.
Example: Making a Field Read-Only After Submission
Once an incident is resolved or closed, you might want to prevent users from changing certain fields like ‘Short Description’ or ‘Description’.
function onLoad(type) {
var state = g_form.getValue('state'); // Assuming 'state' is the field for incident state
// Common values for Resolved or Closed states
var resolvedState = '6'; // Example sys_id or value for Resolved
var closedState = '7'; // Example sys_id or value for Closed
if (state === resolvedState || state === closedState) {
g_form.setReadOnly('short_description', true);
g_form.setReadOnly('description', true);
// Make other fields read-only as needed
}
}
3. Controlling Field Mandatory Status
Ensuring users provide necessary information is crucial for data quality. GlideForm allows you to dynamically make fields mandatory.
g_form.setMandatory(fieldName, isMandatory)
This method sets the mandatory status of a field. Use true to make it mandatory and false to make it optional.
Example: Making ‘Assignment Group’ Mandatory if ‘Assigned To’ is Empty
In a task-like table, if a user assigns the task to themselves, the ‘Assignment Group’ might become optional. If they leave ‘Assigned To’ blank, then ‘Assignment Group’ should be mandatory.
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading || newValue === '') {
return;
}
var assignedToValue = g_form.getValue('assigned_to');
if (assignedToValue === '') {
g_form.setMandatory('assignment_group', true);
} else {
g_form.setMandatory('assignment_group', false);
}
}
4. Working with Choice Lists
Choice lists are a common way to present options to users. GlideForm allows you to dynamically interact with them.
g_form.addOption(fieldName, choiceValue, choiceLabel, choiceIndex)
This method adds a new option to a choice list dynamically. This is incredibly powerful for creating context-sensitive options.
Example: Adding a Custom Priority Option Based on Category
If the ‘Category’ is ‘Network’, you might want to add a “Critical” priority option to the ‘Priority’ choice list.
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading || newValue === '') {
return;
}
var category = g_form.getValue('category');
// Clear existing options related to custom priorities if needed, or handle carefully
// This example assumes you want to ADD an option.
if (category === 'network') {
// Check if 'Critical' option already exists to avoid duplicates
if (g_form.getOption('priority', 'critical')) {
// Option already exists, do nothing or handle as needed
} else {
// Add the 'Critical' option with value 'critical' and label 'Critical - Network Issue'
// Typically, values are numbers or short strings. Let's use a custom value.
// You might need to ensure your backend field supports this custom value.
g_form.addOption('priority', 'network_critical', 'Critical - Network Issue');
g_form.setMandatory('priority', true); // Make priority mandatory if network is chosen
g_form.setValue('priority', 'network_critical'); // Set it to the new option
}
} else {
// If category is not network, you might want to remove the custom option or reset priority
// Removing options can be tricky. Often easier to manage visibility/mandatory of default options.
// For simplicity, let's just ensure it's not mandatory and set a default if applicable.
g_form.setMandatory('priority', false); // Make it optional again if not network
// If you need to remove it: g_form.removeOption('priority', 'network_critical');
// Be cautious when removing options as it might affect other logic.
}
}
g_form.removeOption(fieldName, choiceValue)
This method removes a specific option from a choice list.
Example: Removing ‘Not Applicable’ Option for Certain Situations
If a task is assigned to a specific user, you might remove the “Not Applicable” option from a “Reason for Delay” choice list.
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading || newValue === '') {
return;
}
var assignedTo = g_form.getValue('assigned_to');
if (assignedTo !== '') {
// Remove 'Not Applicable' if assigned to someone
g_form.removeOption('u_reason_for_delay', 'not_applicable'); // Assuming 'not_applicable' is the value
} else {
// Re-add it if needed, or ensure it's present if the assignment is cleared
// Note: Re-adding is not directly supported by a simple addOption if it was removed.
// Often, managing visibility/mandatory of choices is a better approach than removing.
// If you must remove and re-add, you might need to refresh the choice list or use other methods.
// A safer approach is often to manage visibility of the choice itself if possible, or use UI Policies.
}
}
Troubleshooting Note: Removing and re-adding options can be complex. If you find issues, consider using UI Policies to control the visibility or mandatory status of default choices instead of manipulating the options themselves.
g_form.getOption(fieldName, choiceValue)
This method checks if a specific option exists in a choice list. It returns the option object if found, otherwise null.
Example: Checking for an Existing Option Before Adding
As seen in the addOption example, it’s good practice to check if an option already exists to prevent duplicates.
if (g_form.getOption('priority', 'network_critical')) {
gs.log("Custom priority already exists."); // This log would be server-side if used in a Business Rule. Client-side, use g_form.addInfoMessage or console.log.
console.log("Custom priority already exists.");
} else {
g_form.addOption('priority', 'network_critical', 'Critical - Network Issue');
}
5. User Information: Knowing Who’s Using the Form
Contextualizing form behavior based on the logged-in user is a common requirement. While much of this can be done server-side, client-side scripts can leverage user information for immediate UI feedback.
Client-Side User ID:
While there isn’t a direct g_form.getCurrentUserID(), you can often access user information via the g_user object. The user’s system ID (sys_id) is crucial.
// Get the current logged-in user's sys_id
var currentUserID = g_user.userID;
console.log("Current User ID:", currentUserID); // e.g., "6816f79cc0a8016401c5a33be04be441"
// You can also get display name and other details
var currentUserName = g_user.getFullName();
console.log("Current User Name:", currentUserName);
Server-Side User ID:
On the server-side, retrieving the current user’s ID is straightforward using gs.getUserID().
// Server-side example (e.g., in a Business Rule)
var currentUserID = gs.getUserID();
gs.info("Server-side User ID: " + currentUserID);
Checking Group Membership:
This is primarily a server-side operation as it often involves database lookups. While you *could* pass group membership information to the client via a GlideAjax call, direct client-side checking isn’t as robust.
Server-Side Check:
// Server-side example
var isMemberOfIT = gs.getUser().isMemberOf('ITIL Users'); // Replace 'ITIL Users' with your actual group name
if (isMemberOfIT) {
gs.info("User is a member of ITIL Users.");
} else {
gs.info("User is NOT a member of ITIL Users.");
}
Client-Side Alternative (via GlideAjax): For client-side logic that needs to know group membership, you’d typically create a Script Include (callable via GlideAjax) on the server that performs the gs.getUser().isMemberOf() check and returns the result to the client.
6. Setting Default Values
Populating fields with default values when a form first loads is a common requirement. While dictionary entries can provide defaults, client scripts offer more dynamic control.
Dictionary Defaults: For simple, static default values, configure them directly in the field’s dictionary entry. This is the most performant way.
Client-Side Defaults (using onLoad scripts): For defaults that depend on other fields, the logged-in user, or other dynamic conditions, use an onLoad client script.
Example: Setting Default Values on a New Incident
When a new incident is created, automatically set the ‘Caller’ to the currently logged-in user and set the ‘Impact’ and ‘Urgency’ to ‘Medium’ by default.
function onLoad(type) {
// Set the caller to the current user
g_form.setValue('caller_id', g_user.userID);
// Set default impact and urgency
g_form.setValue('impact', '2'); // Assuming '2' is the value for Medium Impact
g_form.setValue('urgency', '2'); // Assuming '2' is the value for Medium Urgency
// You might also want to set a default assignment group for certain categories
var category = g_form.getValue('category');
if (category === 'hardware') {
// Set a default hardware assignment group (using sys_id)
// g_form.setValue('assignment_group', 'sys_id_of_hardware_group');
}
// Example: Setting a default value for a field that is initially hidden
// This is useful if you plan to reveal it later based on a condition.
// g_form.setValue('u_internal_notes', 'Initial notes.');
}
Troubleshooting: If default values aren’t appearing, ensure your client script is correctly set to run onLoad and that it’s applied to the correct table and conditions. Also, check if other scripts (like Business Rules or UI Policies) might be overwriting these defaults.
7. Getting and Setting Values for Reference Fields (Deep Dive)
Reference fields are fundamental. Understanding how to get and set their values is key.
- Getting Value:
g_form.getValue('reference_field_name')returns thesys_idof the referenced record. - Setting Value:
g_form.setValue('reference_field_name', 'sys_id_of_related_record')sets the field to the specified record. - Setting Display Value:
g_form.setDisplayValue('reference_field_name', 'Display Name of Related Record')attempts to find and set the record using its display name. Use with caution due to potential ambiguity.
Example: Setting ‘Company’ based on ‘User’
When a ‘User’ is selected, automatically populate the ‘Company’ field with the user’s company.
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading || newValue === '') {
return;
}
var userID = g_form.getValue('caller_id'); // Assuming caller_id is the reference to sys_user
if (userID) {
// Use GlideAjax to efficiently get the user's company sys_id from the server
var ga = new GlideAjax('com.glide.script.UserPreference'); // A common utility script, or create your own
ga.addParam('sysparm_name', 'getUserInfo'); // A custom function in your script include
ga.addParam('sysparm_user_id', userID);
ga.getXMLAnswer(function(answer) {
if (answer) {
var userInfo = JSON.parse(answer);
if (userInfo && userInfo.company) {
g_form.setValue('company', userInfo.company); // Set the company field
} else {
g_form.clearValue('company'); // Clear company if user has no company
}
}
});
} else {
g_form.clearValue('company');
}
}
Note: The example above uses a placeholder for GlideAjax. In a real scenario, you’d create a Script Include that fetches the company sys_id from the sys_user record based on the provided userID.
Server-Side Equivalent for Reference fields:
// Server-side: setting the sys_id of a related user record
current.caller_id.setValue("a1b2c3d4e5f678901234567890abcdef");
// Server-side: setting the company based on caller_id
var userRecord = new GlideRecord('sys_user');
if (userRecord.get(current.caller_id)) {
current.company.setValue(userRecord.company);
}
8. Debugging and Information Messages
Effective debugging is crucial. GlideForm provides methods to help you understand what’s happening.
g_form.addInfoMessage(message)
Displays an informational message to the user at the top of the form. This is great for providing feedback or guiding users.
g_form.addErrorMessage(message)
Displays an error message. These messages typically appear in red and can often prevent form submission if used correctly in validation logic.
console.log()
While not strictly a GlideForm method, console.log() is indispensable for client-side debugging. You can see its output in your browser’s developer console.
Example: Providing Feedback and Validation
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading || newValue === '') {
return;
}
var priorityValue = g_form.getValue('priority');
if (priorityValue === '1') { // Assuming '1' is Critical
g_form.addInfoMessage("Critical priority selected. Please ensure all required fields are complete.");
// Potentially make assignment group mandatory
g_form.setMandatory('assignment_group', true);
} else {
g_form.addInfoMessage("Priority set to " + g_form.getDisplayBox('priority').value + ".");
g_form.setMandatory('assignment_group', false);
}
// Example of validation that might prevent submission
if (g_form.getValue('short_description').length < 5) {
g_form.addErrorMessage("Short Description must be at least 5 characters long.");
console.log("Short Description validation failed.");
// The form might not submit if there are error messages and your script is designed to block it.
// In some cases, you might need to return false from onSubmit scripts, but addErrorMessage is often sufficient for guidance.
}
}
Troubleshooting Common GlideForm Issues
Even experienced developers encounter issues. Here are some common pitfalls and how to address them:
1. Scripts Not Running:
- Check Scope: Ensure your client script is in the correct application scope.
- Table and Conditions: Verify the client script is applied to the correct table and that the conditions (if any) are met.
- Order: If you have multiple client scripts on the same field or event, their execution order can matter. UI Policies run before client scripts by default. You can set an 'Order' field on client scripts.
- Caching: Sometimes, browser or ServiceNow instance caching can cause issues. Clear your browser cache or do a hard refresh (Ctrl+Shift+R or Cmd+Shift+R).
- Field Name Typos: Double-check that you're using the exact backend field names (e.g.,
short_description, notShort Description).
2. `g_form` Object Not Available:
This typically happens if your script is running in the wrong context (e.g., a Business Rule trying to use g_form) or if there's a fundamental issue with the form loading. Ensure your script is defined as a Client Callable script if it's a Script Include intended for GlideAjax. For client scripts, g_form is automatically available.
3. Reference Field Issues:
- Incorrect sys_id: Ensure you're passing the correct
sys_idtog_form.setValue(). - Display Value Ambiguity: If using
g_form.setDisplayValue(), ensure the display name is unique for the referenced table. - Reference Qualifiers: Complex reference qualifiers can sometimes interfere with client-side setting of values if not handled properly.
4. Performance Concerns:
Too many onLoad or onChange scripts, especially those making synchronous GlideAjax calls (which are discouraged), can slow down form loading. Consider:
- Minimize DOM manipulation: Only update what's necessary.
- Use asynchronous GlideAjax: Prefer
getXML()orgetXMLAnswer()over the deprecatedgetXMLSync(). - Leverage UI Policies: For simple visibility, mandatory, and read-only changes, UI Policies are often more performant than client scripts as they are declarative.
- Optimize Server Scripts: If using GlideAjax, ensure your server-side Script Includes are efficient.
Interview Relevance
Understanding GlideForm methods is a cornerstone of ServiceNow client-side development and a frequent topic in technical interviews. Interviewers will often ask about:
- Core Functionality: "How would you make a field read-only based on a condition?" (
g_form.setReadOnly()) - Data Manipulation: "How do you set a default value for a field when a form loads?" (
onLoadscript withg_form.setValue()) - Dynamic UI: "How can you show or hide a section of the form?" (
g_form.setVisible()on fields within the section, org_form.setSectionDisplay()if available for sections) - User Context: "How can you get the current user's ID on the client-side?" (
g_user.userID) - Validation: "How would you add a custom error message to a form?" (
g_form.addErrorMessage()) - Reference Fields: "What's the difference between
setValueandsetDisplayValuefor a reference field?" - Client vs. Server: "When would you use
g_formversus thecurrentobject?" - Advanced Scenarios: Questions involving dynamic choice lists (
addOption,removeOption) or complex UI interactions will test deeper understanding.
Be prepared to explain the purpose of each method, provide simple code examples, and discuss the context in which they are used.
Conclusion
The GlideForm API, accessible through the g_form object, is an indispensable tool for any ServiceNow developer. By mastering methods like getValue, setValue, setVisible, setReadOnly, setMandatory, and those for manipulating choice lists, you can transform static forms into dynamic, user-friendly interfaces.
Remember to always consider the client-side versus server-side execution context and choose the appropriate API (g_form or current) for your task. With practice and a solid understanding of these core methods, you'll be well-equipped to build robust, efficient, and engaging ServiceNow applications.