Mastering OnChange Client Scripts in ServiceNow: A Practical Tutorial
Welcome, ServiceNow enthusiasts and aspiring developers! Today, we’re diving deep into one of the most fundamental and powerful client-side scripting tools in ServiceNow: the OnChange Client Script. If you’ve ever wanted to make your forms more dynamic, responsive, and user-friendly by reacting to changes in field values, then this tutorial is for you.
We’ll break down what OnChange client scripts are, why they’re essential, how to create them, and provide practical, real-world examples. We’ll also touch upon related concepts and offer some tips for troubleshooting and acing those tough ServiceNow interviews.
What Exactly is an OnChange Client Script?
At its core, an OnChange client script is a piece of JavaScript code that executes on the user’s browser (the client-side) whenever the value of a specified field on a ServiceNow form changes. Think of it as an event listener. When a specific field’s value is altered – whether by typing, selecting from a dropdown, or pasting – this script “wakes up” and performs its designated actions.
This is incredibly useful for:
- Validating user input in real-time.
- Dynamically showing or hiding other fields.
- Setting default values for related fields.
- Performing calculations based on other fields.
- Triggering notifications or alerts.
- Fetching data from other tables based on the change.
Unlike UI Policies, which are great for simpler, condition-based actions, OnChange client scripts offer greater flexibility and power when you need to implement custom logic or complex interactions. As one ServiceNow interview question highlights, UI Policies can be enhanced with scripts (by enabling the “Run scripts” checkbox), but for many scenarios where the trigger is a field change, a dedicated OnChange client script is often the cleaner and more direct solution.
Key Takeaway: OnChange client scripts are your go-to for client-side logic that needs to react *specifically* when a field’s value changes.
When Should You Use an OnChange Client Script?
The decision to use an OnChange client script often boils down to the nature of the interaction you need to create. Here are some common scenarios:
- Conditional Field Visibility/Mandatory Status: While UI Policies can handle many of these, if the logic becomes complex or involves interacting with other scripts or external data, a client script might be better. For instance, making a field mandatory only if another field meets a complex set of criteria derived from multiple other fields.
- Data Validation: When a user enters data, you want to immediately check if it’s valid. For example, ensuring a ZIP code format is correct, or that a start date is before an end date.
- Dynamic Field Population: Based on the value entered in one field, you might want to automatically populate another. A classic example is selecting a Category and having the Subcategory field update its choices or automatically set a default based on the category. This ties into the concept of Dependent Values, which are often managed at the dictionary level but can be reinforced or extended with client scripts.
- Performing Calculations: If you have fields that represent numerical values, you might want to calculate a total, a percentage, or an estimated value as soon as the input fields change.
- Interacting with Related Records: You might need to fetch information from a related record or even perform actions on it based on the current form’s field changes.
Interview Relevance: Interviewers often ask about the differences between UI Policies and Client Scripts. Remember that UI Policies are declarative and good for simpler show/hide/mandatory/readonly actions based on conditions. Client Scripts, especially OnChange scripts, are for more procedural, complex JavaScript logic triggered by events. UI Policies are generally preferred for their performance and ease of maintenance when they suffice.
Creating Your First OnChange Client Script
Let’s walk through the process of creating an OnChange client script. We’ll use a practical example: automatically setting the Assignment Group on an Incident record based on the selected Category and Subcategory.
Scenario:
- If the Category is ‘Hardware’ and the Subcategory is ‘Laptop’, assign to ‘Service Desk – Hardware’.
- If the Category is ‘Software’ and the Subcategory is ‘Operating System’, assign to ‘Service Desk – Software’.
- Otherwise, leave the Assignment Group blank.
Step-by-Step Guide:
- Navigate to Client Scripts: In the ServiceNow instance, navigate to System Definition > Client Scripts.
- Click “New”: Click the “New” button to create a new client script record.
- Fill in the Form:
- Name: Give your script a descriptive name, e.g., “Auto Assign Group based on Category/Subcategory”.
- Table: Select the table you want this script to run on. In our example, this is Incident [incident].
- UI Type: Choose Desktop (or All if you want it to run on both desktop and mobile).
- Application: Usually, this will be Global or the specific application scope.
- Active: Ensure this checkbox is checked.
- Configure the Script:
- Client-callable: For OnChange scripts, this is typically left unchecked as they are triggered by form interactions, not direct API calls.
- Type: Select onLoad, onChange, or onSubmit. For this tutorial, we select onChange.
- Field name: This is crucial! Since our logic depends on changes in *both* Category and Subcategory, we will create two OnChange client scripts: one for Category and one for Subcategory. This is a common pattern when logic depends on multiple fields. Let’s start with the Category field. So, select Category here.
- Write the Script: In the Script section, enter your JavaScript code.
Example Script (for Category field):
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading || newValue === '') {
return;
}
// Get the values of Category and Subcategory
var category = g_form.getValue('category');
var subcategory = g_form.getValue('subcategory');
var assignmentGroup = g_form.getReference('assignment_group'); // Use getReference for complex logic or to get sys_id
// Define the logic to set the Assignment Group
if (category === 'hardware' && subcategory === 'laptop') {
// You would typically use sys_ids for assignment groups, but for simplicity,
// let's assume you have display names or know the sys_ids.
// For a real-world scenario, it's best practice to use sys_ids.
// Example: g_form.setValue('assignment_group', 'YOUR_HARDWARE_GROUP_SYS_ID');
// For demonstration, let's just set a clear message or a placeholder.
// In a real scenario, you'd look up the group's sys_id.
g_form.addErrorMessage('Consider assigning to Service Desk - Hardware.');
// To actually set it:
// g_form.setValue('assignment_group', 'sys_id_of_service_desk_hardware');
g_form.setValue('assignment_group', ''); // Clear it for now if not setting specific group
} else if (category === 'software' && subcategory === 'operating_system') {
// Example: g_form.setValue('assignment_group', 'YOUR_SOFTWARE_GROUP_SYS_ID');
g_form.addErrorMessage('Consider assigning to Service Desk - Software.');
// To actually set it:
// g_form.setValue('assignment_group', 'sys_id_of_service_desk_software');
g_form.setValue('assignment_group', ''); // Clear it for now if not setting specific group
} else {
// If no specific conditions are met, clear the assignment group
g_form.setValue('assignment_group', '');
}
}Now, create a second OnChange client script for the Subcategory field. The script will be very similar, but it needs to check the Category value as well.
Example Script (for Subcategory field):
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading || newValue === '') {
return;
}
// Get the values of Category and Subcategory
var category = g_form.getValue('category');
var subcategory = g_form.getValue('subcategory');
// Define the logic to set the Assignment Group
if (category === 'hardware' && newValue === 'laptop') { // newValue refers to the subcategory change
// Example: g_form.setValue('assignment_group', 'YOUR_HARDWARE_GROUP_SYS_ID');
g_form.addErrorMessage('Consider assigning to Service Desk - Hardware.');
g_form.setValue('assignment_group', ''); // Clear it for now
} else if (category === 'software' && newValue === 'operating_system') { // newValue refers to the subcategory change
// Example: g_form.setValue('assignment_group', 'YOUR_SOFTWARE_GROUP_SYS_ID');
g_form.addErrorMessage('Consider assigning to Service Desk - Software.');
g_form.setValue('assignment_group', ''); // Clear it for now
} else {
// If no specific conditions are met, clear the assignment group
g_form.setValue('assignment_group', '');
}
}Important Note on Values: ServiceNow often stores values in lowercase for choices and categories. It’s crucial to inspect the actual values in your system (e.g., by checking the dictionary entry for the choice list or by using gs.log() server-side for debugging) to ensure your script uses the correct string representations. The example above uses lowercase strings for demonstration.
Setting Assignment Group: In a real-world scenario, you would use g_form.setValue('assignment_group', 'sys_id_of_your_group');. You can find the sys_id of a group by navigating to User Administration > Groups, clicking on the desired group, and looking at the URL in your browser’s address bar (it will contain sys_id=...).
Key G_form Methods for OnChange Scripts
The g_form object is your best friend when working with client scripts. Here are some of the most commonly used methods:
g_form.getValue(fieldName): Retrieves the current value of a field. This is essential for checking what’s currently in a field.g_form.setValue(fieldName, value): Sets the value of a field. This is how you update fields dynamically.g_form.setDisplayValue(fieldName, displayValue): Sets the display value of a field. This is particularly useful for reference fields where you want to set the human-readable name instead of the sys_id, althoughsetValueis often sufficient if you provide the sys_id.g_form.setMandatory(fieldName, boolean): Makes a field mandatory (true) or optional (false).g_form.setReadOnly(fieldName, boolean): Makes a field read-only (true) or editable (false).g_form.setVisible(fieldName, boolean): Shows (true) or hides (false) a field.g_form.addErrorMessage(message): Displays an error message to the user, typically at the top of the form. This is great for validation.g_form.getReference(fieldName, callback): Retrieves a reference field’s record. This is powerful for getting details from related records. It’s asynchronous, so it requires a callback function.
Interview Relevance: Be prepared to discuss these g_form methods. Knowing when to use getValue vs. getReference, or setValue vs. setDisplayValue, shows a deeper understanding.
Understanding the OnChange Function Parameters
The onChange function in a client script receives several parameters:
control: This parameter represents the UI element (the field) that triggered the script.oldValue: The value the field had *before* the change.newValue: The value the field has *after* the change.isLoading: A boolean that istrueif the form is currently loading and the script is being run as part of the initial load (e.g., if the script runs on load for a field that has a default value). You usually want to return ifisLoadingis true to avoid unintended actions.isTemplate: A boolean that istrueif the script is running as part of a template application.
The if (isLoading || newValue === '') { return; } check at the beginning of most OnChange scripts is a best practice. It prevents the script from running unnecessarily when the form is just loading or when the field is being cleared.
Advanced Concepts and Considerations
Working with Reference Fields
Reference fields are common, and their behavior can be complex. When working with them in OnChange scripts:
- Getting the sys_id:
g_form.getValue('reference_field_name')will typically give you the sys_id of the selected record. - Getting the Display Value: For displaying names, you might use
g_form.getDisplayBox('reference_field_name').valueor, more robustly,g_form.getReference('reference_field_name', function(gr) { console.log(gr.name); });. - Setting Values: To set a reference field, you almost always provide the sys_id using
g_form.setValue('reference_field_name', 'sys_id_of_related_record');.
The interview question about Reference Qualifiers (Simple, Dynamic, Advanced) is highly relevant here. While not directly part of client scripting, the ability to filter reference fields is often intertwined with dynamic form behavior that client scripts help orchestrate. For example, a client script might change the value of a field that then triggers a dynamic reference qualifier.
Dependent Fields
As described in the reference material (“Dependent Values in Dictionary”), dependent fields create cascaded dropdowns. While often configured at the dictionary level, an OnChange client script can further enhance this by:
- Manually clearing or setting dependent field values based on complex logic.
- Performing actions *after* a dependent value has been selected or changed.
For instance, if a user selects ‘Network’ as Category and ‘Router’ as Subcategory, an OnChange script could then automatically set a specific hardware model or fetch configuration details.
Field Types
Understanding the variety of field types (String, Reference, Choice, Date/Time, etc.) is crucial because the way you get and set values, and the type of validation you apply, can differ. For example, comparing dates requires different logic than comparing strings.
Attributes
Attributes (like no_email, no_attachment) are dictionary-level configurations that alter field behavior. While client scripts can override or react to these, they don’t directly set attributes. However, understanding attributes helps you grasp the overall field behavior context.
Dictionary Overrides
Dictionary overrides allow tailoring fields for specific tables. A client script might leverage a field that has been overridden for specific behavior. For example, if a field has a default value defined via a dictionary override, your OnChange script might need to account for that default value.
Troubleshooting Common OnChange Script Issues
Even experienced developers encounter glitches. Here are common pitfalls and how to address them:
Troubleshooting Tips:
- Incorrect Field Names: Double-check that the field names in your script (e.g.,
'category','assignment_group') exactly match the ‘Column name’ in the field’s dictionary entry. Typos are extremely common! - Case Sensitivity: Values in choice lists or dropdowns might be case-sensitive. Ensure your script uses the exact casing. Use
g_form.getValue('field_name').toLowerCase()to normalize if unsure. - Asynchronous Operations (
getReference): If you’re usingg_form.getReference, remember it’s asynchronous. Any code that relies on the data fetched bygetReference*must* be inside the callback function. - Script Not Running:
- Is the script Active?
- Is the correct Table selected?
- Is the correct Field name selected for the OnChange trigger?
- Is the UI Type appropriate (Desktop, Mobile, All)?
- Are there any syntax errors in your script? Use the browser’s developer console (F12) to check for JavaScript errors.
- Logic Errors: The script runs, but it doesn’t do what you expect.
- Use
console.log(): The best debugging tool on the client-side. Addconsole.log('Value of category:', g_form.getValue('category'));or similar statements to see what values your script is working with. You’ll find the output in your browser’s developer console. - Test Incrementally: Build your script piece by piece. Get one part working, then add the next.
- Check Conditions Carefully: Ensure your
ifandelse ifstatements are evaluating correctly.
- Use
- Performance Issues: If your form becomes slow, especially on load or when changing fields, you might have too many complex client scripts, or inefficient scripts.
- Prioritize UI Policies for simple tasks.
- Optimize your JavaScript code.
- Avoid making synchronous calls if possible (though less common now with modern GlideAjax).
- Consider using GlideAjax for server-side operations rather than trying to do complex data lookups directly in client scripts.
- UI Type Mismatches: Scripts set to “Desktop” won’t run on the mobile UI, and vice-versa, unless set to “All.”
When to Use GlideAjax Instead of Direct Client Script Logic
While OnChange client scripts are great for client-side logic, they have limitations. They cannot directly query the database or perform server-side operations. If your OnChange event needs to:
- Query a large dataset.
- Perform complex business logic that requires server-side access.
- Update records on the server in a way that a client script can’t easily do.
Then, it’s time to use GlideAjax. You’ll write a script include (a server-side script) that your OnChange client script can call asynchronously. The client script sends data to the script include, the script include performs the server-side action (e.g., queries a table using GlideRecord, like creating incident records using var gr = new GlideRecord('incident'); gr.initialize(); ... gr.insert();), and then returns data back to the client script.
Interview Relevance: Be ready to explain GlideAjax. It’s a standard way to bridge the gap between client-side scripting and server-side processing. Knowing how to create a script include and call it from a client script is a valuable skill.
Conclusion
OnChange client scripts are a cornerstone of building interactive and intelligent forms in ServiceNow. By mastering their use, you can significantly enhance user experience, improve data quality, and streamline workflows. Remember to start simple, use the g_form object effectively, debug with console.log(), and know when to leverage GlideAjax for more complex server-side interactions.
As you continue your ServiceNow journey, keep practicing and experimenting. The more you build, the more intuitive these powerful scripting tools will become.