Incident Table Records: Best Practices for Effective Management






Mastering Incident Table Records: Your Definitive Guide to ServiceNow Scripting with GlideRecord and GlideForm


Mastering Incident Table Records: Your Definitive Guide to ServiceNow Scripting with GlideRecord and GlideForm

Hey there, fellow ServiceNow enthusiast! Ever felt like you’re trying to tame a wild beast when it comes to customizing your instance or automating crucial IT processes? Well, you’re in the right place. Today, we’re diving deep into the heart of ServiceNow scripting, specifically focusing on how to effortlessly interact with the database and dynamic forms. Our journey will center around Incident records, a cornerstone of IT Service Management (ITSM), but the principles you learn here are universally applicable across the platform.

Whether you’re a budding ServiceNow developer, an experienced administrator looking to sharpen your skills, or preparing for that crucial interview, understanding GlideRecord and GlideForm is non-negotiable. These APIs are your superpowers, enabling you to build robust, efficient, and user-friendly solutions. So, grab your coffee, roll up your sleeves, and let’s get coding!

The Heart of ServiceNow Scripting: A Glide API Overview

At its core, ServiceNow gives us incredible flexibility to extend and customize its platform, and the Glide API is our primary toolkit for making that happen. Think of Glide APIs as a collection of pre-built JavaScript classes and methods that allow us to interact with various parts of the ServiceNow ecosystem without having to write complex SQL queries or manipulate DOM elements directly.

Why do we use them? Simple: they abstract away the underlying complexities. Instead of grappling with database schemas or intricate browser APIs, you get a clean, developer-friendly interface to get things done. Each API is packed with methods, each designed to perform a specific operation, making your scripting tasks more manageable and efficient.

Client-Side vs. Server-Side: Understanding the Divide

ServiceNow scripting generally falls into two major categories, each with its own set of Glide APIs, serving distinct purposes:

  • Client-Side APIs: These APIs run directly in the user’s web browser. They’re all about manipulating the user interface (UI), responding to user actions, and providing real-time feedback. When you see a field hide or become mandatory as you type, that’s client-side scripting in action.
    • GlideForm (g_form): Your go-to for controlling form elements.
    • GlideUser (g_user): Accessing information about the currently logged-in user.
    • GlideAjax: Making asynchronous calls to the server without reloading the page.
    • GlideDialogWindow: Creating custom pop-up windows.
  • Server-Side APIs: These APIs execute on the ServiceNow instance’s server. They’re ideal for database operations, backend logic, integrations, and anything that requires secure access to data or manipulation of records.
    • GlideRecord: The undisputed champion for database CRUD (Create, Read, Update, Delete) operations.
    • GlideSystem (gs): Providing utility functions for logging, printing messages, and accessing system properties.
    • GlideDate and GlideDateTime: Handling date and time objects.
    • GlideAggregation: Performing aggregate calculations on record sets.

Understanding this fundamental distinction is crucial. You wouldn’t use a hammer to drive a screw, right? Similarly, knowing when to use a client-side API versus a server-side one is key to writing effective and performant ServiceNow scripts.

Unlocking Database Power: Deep Dive into GlideRecord

If you’re going to do any serious scripting in ServiceNow, you absolutely need to master GlideRecord. This isn’t just “another API”; it’s arguably the most common and vital one you’ll encounter. Think of GlideRecord as ServiceNow’s native JavaScript class (though under the hood, it’s a wrapper around a Java class) that acts as your direct line to the database. It lives and breathes on the server-side, meaning all your interactions with GlideRecord happen securely and efficiently on your ServiceNow instance.

Its primary superpower? Performing all your database CRUD (Create, Read, Update, Delete) operations without you ever having to write a single line of SQL. Yes, you heard that right! No complex SQL joins, no obscure syntax – just plain JavaScript methods to fetch, filter, modify, or remove data. It elegantly handles both rows and columns, translating your JavaScript calls into the appropriate SQL queries behind the scenes.

GlideRecord Architecture: Scripting, Not SQL

The beauty of GlideRecord lies in its abstraction. Instead of directly passing SQL queries to your ServiceNow database, you use intuitive JavaScript methods. For instance, to get all active incidents, you don’t write SELECT * FROM incident WHERE active = TRUE;. Instead, you’d write something like this:

var incidentGR = new GlideRecord('incident');
incidentGR.addQuery('active', true);
incidentGR.query();
while (incidentGR.next()) {
    // Do something with incidentGR.number or other fields
}

This approach makes your code cleaner, more readable, and significantly reduces the learning curve for developers who might not be SQL experts. It’s a game-changer for building robust server-side logic in ServiceNow.

Important Precaution: Test Before You Deploy!

Before you ever deploy any GlideRecord script to a production environment, you MUST test it thoroughly on a non-production instance (like your Dev or Test instance). An incorrectly constructed query – perhaps with an invalid field name, a typo, or flawed logic – can lead to unexpected and potentially disastrous results, including data loss. Methods like insert(), update(), deleteRecord(), and deleteMultiple(), when used with an invalid query, can severely impact your data integrity. Always, always, always validate your queries and test your scripts in a safe environment first!

Essential GlideRecord Methods You’ll Use Daily

The GlideRecord API is vast, offering a plethora of methods. Here’s a quick rundown of some of the most frequently used ones, categorized for clarity:

Querying and Filtering Data

  • query(): Executes the query you’ve built.
  • addQuery(field, value) or addQuery(field, operator, value): Adds a condition to your query.
  • addEncodedQuery(encodedQueryString): Adds a complex query string, often copied directly from a list filter.
  • addActiveQuery() / addInactiveQuery(): Convenience methods for filtering active/inactive records.
  • get(sys_id) or get(field, value): Retrieves a single record based on its unique ID or a field-value pair.
  • setLimit(number): Restricts the number of records returned by the query.
  • orderBy(field) / orderByDesc(field): Sorts the results in ascending or descending order.
  • chooseWindow(first, last): Selects a subset of records from the result set (like pagination).
  • addNullQuery(field) / addNotNullQuery(field): Filters for records where a specific field is null or not null.
  • addJoinQuery(joinTable, primaryField, joinField): Joins tables for more complex queries.

Iterating and Retrieving Data

  • next(): Moves to the next record in the query result set. Essential for looping through results.
  • hasNext(): Checks if there are more records in the result set.
  • getRowCount(): Returns the total number of records in the result set.
  • getValue(field): Retrieves the actual database value of a field.
  • getDisplayValue(field): Retrieves the display value (what the user sees) of a field.
  • getUniqueValue(): Gets the sys_id of the current record.
  • getTableName(): Returns the name of the table the GlideRecord is currently querying.
  • getLink(boolean): Generates a URL link to the current record.

Manipulating Records (CRUD Operations)

  • initialize(): Creates an empty record object, ready for insertion.
  • setValue(field, value): Sets the value of a specific field.
  • insert(): Inserts the current record into the database.
  • update(): Updates the current record in the database.
  • updateMultiple(): Updates all records matching the current query.
  • deleteRecord(): Deletes the current record.
  • deleteMultiple(): Deletes all records matching the current query.

Utility and Access Control

  • isValid(): Checks if the GlideRecord object refers to a valid table.
  • isValidField(field): Checks if a specified field exists in the table.
  • isValidRecord(): Checks if a record was actually returned by a get() or query() operation.
  • isNewRecord(): Checks if the current record is new and hasn’t been inserted yet.
  • canCreate(), canRead(), canWrite(), canDelete(): Checks if the current user has ACL permissions to perform these operations on the record/table.
  • autoSysFields(boolean): Enables or disables the automatic update of system fields (sys_updated_by, sys_created_on, etc.) during an update.
  • setWorkflow(boolean): Controls whether business rules, workflows, and other engine processes are run when a record is updated.

Pro Tip: Script – Background Application!

The best place to test your server-side GlideRecord scripts is the “Script – Background” application in ServiceNow. Navigate to it via the Filter Navigator. It provides a quick way to execute arbitrary JavaScript on the server and see the output using gs.print() or gs.info().

Putting GlideRecord to Work: Practical Exercises (Incident Table Focus)

Let’s get our hands dirty with some practical examples using the Incident table. These exercises will help solidify your understanding of how these methods work in a real-world context.

Getting Started: Basic Output and Calculations

Before diving into records, let’s ensure we can print output and do simple calculations:

// Exercise 1: How to get result(output) in Servicenow?
gs.print('Welcome to ServiceNow Academy');
gs.info('Welcome to ServiceNow Academy');
// Result: Welcome to ServiceNow Academy (in the output console)

// Exercise 2: Write a simple program to add two numbers
var a = 10;
var b = 20;
var c = a + b; // You can also directly print (a + b)
gs.print(c);
// Result: 30

gs.print() and gs.info() are your best friends for debugging server-side scripts, showing output in the Script – Background console or system logs.

Querying and Looping Through Records

This is where GlideRecord truly shines. Let’s fetch some incidents!

// Exercise 3: Working with query() method
var inc = new GlideRecord('incident'); // Instantiate GlideRecord for the 'incident' table
inc.query(); // Execute the query (no conditions, so it fetches all incidents)
while (inc.next()) { // Loop through each record found
    gs.print(inc.number); // Print the 'number' field of the current incident
}
// Result: Prints all incident numbers in your instance. This can be a LOT of records!

The query() method fetches records, and while (inc.next()) is the standard pattern to iterate over the results.

Filtering Records with addQuery()

Finding specific records is a common task. addQuery() allows you to set conditions.

// Exercise 4: Display priority-1 tickets from incident table
var inc = new GlideRecord('incident');
inc.addQuery('priority', '1'); // Add a condition: priority equals 1
inc.query();
while (inc.next()) {
    gs.print(inc.number);
}
// Result: Prints all incident numbers where priority is '1 - Critical'.

// Exercise 5: Working with Multiple Queries (AND condition by default)
var inc = new GlideRecord('incident');
inc.addQuery('active', true);          // Query 1: active records
inc.addQuery('priority', '1');         // Query 2: priority is 1
inc.addQuery('category', 'software');  // Query 3: category is software
inc.query();
while (inc.next()) {
    gs.print(inc.number);
}
// Result: Prints incident numbers that are active AND priority 1 AND category software.

When you use multiple addQuery() statements, they are implicitly joined with an AND operator.

The Power of addEncodedQuery()

For complex queries, or when you want to use advanced operators, addEncodedQuery() is your friend. It’s often easier to build the query in a list view and then copy it.

// Exercise 6: Using addEncodedQuery()
// Step 1-5: Go to Incident list, apply filter: Active = true AND Priority = 1 AND Category = Software.
//           Right-click the filter breadcrumbs, select "Copy query".
//           You'll get something like: 'active=true^category=software^priority=1'

// Step 6: Script
var inc = new GlideRecord('incident');
inc.addEncodedQuery('active=true^category=software^priority=1'); // Paste your copied query here
inc.query();
while (inc.next()) {
    gs.print(inc.number);
}
// Result: Prints incident numbers matching the encoded query.

// Exercise 6 (Part 2): Encoded Query set to a variable
var ecq = 'active=true^category=software^priority=1'; // Store query in a variable
var inc = new GlideRecord('incident');
inc.addEncodedQuery(ecq); // Use the variable
inc.query();
while (inc.next()) {
    gs.print(inc.number);
}
// Result: Same as above. Excellent for reusing complex queries.

Advanced Query Operators

addQuery() isn’t just for equality. You can use various operators:

  • Comparison: =, !=, >, >=, <, <=
  • String operators (case-insensitive unless noted): IN, NOT IN, STARTSWITH, ENDSWITH, CONTAINS, DOES NOT CONTAIN
// Exercise 7: Get Active and Priority is less than or equal to 2
var inc = new GlideRecord('incident');
inc.addActiveQuery(); // Shortcut for 'active=true'
inc.addQuery('priority', '<=', '2'); // Using the <= operator
inc.query();
while (inc.next()) {
    gs.print(inc.number + ' Priority: ' + inc.priority.getDisplayValue());
}
// Result: Prints incident numbers with a priority of 1 (Critical) or 2 (High).

// Exercise 8: Working with <= and CONTAINS
var inc = new GlideRecord('incident');
inc.addActiveQuery();
inc.addQuery('priority', '<=', '2');
inc.addQuery('short_description', 'CONTAINS', 'SAP'); // Find short descriptions containing "SAP"
inc.query();
while (inc.next()) {
    gs.print(inc.number + ' ' + inc.short_description);
}
// Result: Prints active incidents with priority <= 2 and "SAP" in their short description.

// Exercise 9: Working with IN operator and print category of Software and Hardware
var cat = ['software', 'hardware']; // Array of categories
var inc = new GlideRecord('incident');
inc.addQuery('category', 'IN', cat); // 'IN' operator to match any value in the array
inc.query();
while (inc.next()) {
    gs.print(inc.getValue('number') + ' Category: ' + inc.getValue('category'));
}
// Result: Prints incidents where the category is either 'software' or 'hardware'.

// Exercise 10: Working with STARTSWITH Operator
var inc = new GlideRecord('incident');
inc.addQuery('category', 'STARTSWITH', 'net'); // Find categories starting with 'net' (e.g., 'network')
inc.query();
while (inc.next()) {
    gs.print(inc.number + ' Category: ' + inc.category.getDisplayValue());
}
// Result: Prints incidents with categories starting with 'net'.

Convenience Query Methods: addActiveQuery() and addInactiveQuery()

// Exercise 11: Using addActiveQuery()
var inc = new GlideRecord('incident');
inc.addActiveQuery(); // Equivalent to inc.addQuery('active', true);
inc.addQuery('priority', '1');
inc.query();
while (inc.next()) {
    gs.info(inc.number);
}
// Result: Prints active incidents with priority 1.

// Exercise 12: Using addInactiveQuery()
var inc = new GlideRecord('incident');
inc.addInactiveQuery(); // Equivalent to inc.addQuery('active', false);
inc.addQuery('priority', '1');
inc.query();
while (inc.next()) {
    gs.print(inc.number);
}
// Result: Prints inactive incidents (e.g., Closed, Resolved) with priority 1.

Ordering and Limiting Results

// Exercise 13: Working with orderBy() (Ascending)
var inc = new GlideRecord('incident');
inc.addQuery('priority', '1');
inc.addQuery('category', 'software');
inc.orderBy('short_description'); // Order by short_description in ascending order
inc.query();
while (inc.next()) {
    gs.print(inc.number + ' ' + inc.short_description);
}
// Result: Prints active incidents with priority 1, category software, sorted by short description (A-Z).

// Exercise 14: Working with orderByDesc() (Descending)
var inc = new GlideRecord('incident');
inc.addQuery('priority', '1');
inc.addQuery('category', 'software');
inc.orderByDesc('short_description'); // Order by short_description in descending order
inc.query();
while (inc.next()) {
    gs.print(inc.number + ' ' + inc.short_description);
}
// Result: Prints active incidents with priority 1, category software, sorted by short description (Z-A).

// Exercise 15: Working with setLimit()
var inc = new GlideRecord('incident');
inc.addQuery('priority', '1');
inc.orderByDesc('sys_created_on'); // Often used with orderBy for 'latest' records
inc.setLimit(10); // Display only the first 10 records after sorting
inc.query();
while (inc.next()) {
    gs.print(inc.number + ' ' + inc.short_description);
}
// Result: Prints the 10 most recently created incidents with priority 1.

Retrieving Single Records with get()

// Exercise 16: Get record sys_id depends on INC number or Get incident record number depends on sys_id
var inc = new GlideRecord('incident');
// Option 1: Get by field-value pair
inc.get('number', 'INC0009005'); // Fetches the incident with this number
gs.print('Sys_id for INC0009005: ' + inc.sys_id);
// Result: Prints the sys_id related to incident number INC0009005

// Option 2: Get by sys_id (if you know it)
// var incidentSysId = 'YOUR_SYS_ID_HERE'; // Replace with an actual sys_id
// inc.get(incidentSysId);
// gs.print('Incident number for ' + incidentSysId + ': ' + inc.number);
// Result: Prints the incident number related to the given sys_id.

Counting Records with getRowCount()

// Exercise 17: Display total number of records from a table (Incident)
var inc = new GlideRecord('incident');
inc.query(); // No conditions, so it fetches all
gs.print('Total incidents: ' + inc.getRowCount());
// Result: Prints the total count of incident records.

// Exercise 18: Display all active users in our sys_user table
var user = new GlideRecord('sys_user'); // GlideRecord on the User table
user.addQuery('active', true);
user.query();
gs.print('Active users are: ' + user.getRowCount());
// Result: Prints the number of active users in the 'sys_user' table.

Fetching Field Values: getValue() vs. getDisplayValue()

// Exercise 19: Get value of particular field in the table (getValue)
var inc = new GlideRecord('incident');
inc.addQuery('active', true);
inc.setLimit(5); // Just to limit output for readability
inc.query();
while (inc.next()) {
    gs.print('Short Description: ' + inc.getValue('short_description'));
}
// Result: Prints the raw value of the short_description field for the first 5 active incidents.

// Exercise 20: Print display value instead of actual value (getDisplayValue)
var inc = new GlideRecord('incident');
inc.addQuery('priority', '1');
inc.setLimit(3);
inc.query();
while (inc.next()) {
    // For reference fields or choice lists, getValue() gives the sys_id/integer, getDisplayValue() gives the label.
    gs.print('Priority (Value): ' + inc.getValue('priority') + ' | Priority (Display): ' + inc.priority.getDisplayValue());
    gs.print('Caller (Value): ' + inc.getValue('caller_id') + ' | Caller (Display): ' + inc.caller_id.getDisplayValue());
}
// Result: Prints both the numeric value (e.g., '1') and the display label (e.g., '1 - Critical') for priority.
// It also shows the sys_id and display name for the caller_id reference field.

Creating New Records: initialize() and insert()

// Exercise 21: Create a new incident record
var inc = new GlideRecord('incident');
inc.initialize(); // Prepares a new, empty record
inc.category = 'network'; // Directly set field values
inc.short_description = 'Urgent Firewall Issue Reported';
inc.priority = '1';
inc.caller_id = '6816f79cc0a80164000902630b912235'; // Set caller_id with a valid sys_id (e.g., Abel Tuter)
inc.insert(); // Saves the new record to the database
gs.print('New Incident Created: ' + inc.number);
// Result: Creates a new incident record and prints its number (e.g., INC0010042).

Updating Existing Records: update() and updateMultiple()

// Exercise 22: Update a single specific record
var inc = new GlideRecord('incident');
inc.get('number', 'INC0000057'); // Fetch the record to update
if (inc.isValidRecord()) { // Always check if the record was found!
    inc.setValue('state', '2'); // Set state to '2' (In Progress)
    inc.update(); // Save the changes
    gs.print('Incident ' + inc.number + ' updated to state: ' + inc.state.getDisplayValue());
} else {
    gs.print('Incident INC0000057 not found.');
}
// Result: Updates the state of incident INC0000057 to 'In Progress'.

// Exercise 23: Update multiple records with updateMultiple()
var inc = new GlideRecord('incident');
inc.addQuery('category', 'hardware'); // Query for incidents with category 'hardware'
inc.setValue('category', 'software'); // Change their category to 'software'
// inc.updateMultiple(); // Uncomment to run this. BE CAREFUL with updateMultiple!
gs.print('Would have updated ' + inc.getRowCount() + ' records. (Action commented out for safety)');
// Result: Updates all incidents matching the query from 'hardware' category to 'software'.
// Note: ALWAYS test updateMultiple/deleteMultiple on non-production first!

Deleting Records: deleteRecord() and deleteMultiple()

// Exercise 24: Delete a single record
var inc = new GlideRecord('incident');
inc.get('number', 'INC0010013'); // Specify the record to delete
if (inc.isValidRecord()) {
    inc.deleteRecord(); // Permanently delete the record
    gs.print('Incident ' + inc.number + ' deleted.');
} else {
    gs.print('Incident INC0010013 not found for deletion.');
}
// Result: Deletes incident INC0010013. USE WITH EXTREME CAUTION!

// Exercise 25: Delete multiple records with deleteMultiple()
var inc = new GlideRecord('incident');
inc.addQuery('priority', '4'); // Query for incidents with priority '4 - Low'
inc.query(); // Execute the query to find them
// inc.deleteMultiple(); // Uncomment to run this. EXTREME CAUTION ADVISED!
gs.print('Would have deleted ' + inc.getRowCount() + ' records with priority 4. (Action commented out for safety)');
// Result: Deletes all incidents with priority '4 - Low'.
// Again, this is a powerful method. Ensure your query is correct!

Access Control Checks: canCreate(), canRead(), canWrite(), canDelete()

These methods are useful for checking user permissions before attempting an operation, especially in custom UI actions or scheduled jobs.

// Exercise 26: Checking user permissions
var inc = new GlideRecord('incident');
gs.print('Can current user create incident records? ' + inc.canCreate());
inc.get('number', 'INC0000057'); // Get an existing record
if (inc.isValidRecord()) {
    gs.print('Can current user read INC0000057? ' + inc.canRead());
    gs.print('Can current user write to INC0000057? ' + inc.canWrite());
    gs.print('Can current user delete INC0000057? ' + inc.canDelete());
}
// Result: True or False based on the current user's roles and ACLs.

Controlling System Fields and Workflows: autoSysFields() and setWorkflow()

Sometimes you need to update a record without triggering business rules or modifying system fields like `sys_updated_on`.

// Exercise 27: Update multiple records without updating system fields or running workflows
var inc = new GlideRecord('incident');
inc.addQuery('state', '1'); // Find incidents in 'New' state
inc.setLimit(2); // Limiting for safe testing
inc.query();
while (inc.next()) {
    inc.autoSysFields(false); // Do NOT update sys_updated_by, sys_updated_on, etc.
    inc.setWorkflow(false);   // Do NOT run business rules, workflows, etc.
    inc.setValue('state', '2'); // Set state to 'In Progress'
    inc.update();
    gs.print('Incident ' + inc.number + ' state updated to ' + inc.state.getDisplayValue() + ' without system field updates or workflow triggers.');
}
// Result: Updates specified incidents, but their 'Updated' fields and related system processes remain unchanged.
// Note: autoSysFields(false) has limitations in scoped applications.

More Utility Methods

// Exercise 28: Using getTableName()
var gr = new GlideRecord('change_request');
gs.print('GlideRecord table name: ' + gr.getTableName());
// Result: Display current table name: 'change_request'

// Exercise 29: Using getLink() and gs.getProperty()
var inc = new GlideRecord('incident');
inc.addActiveQuery();
inc.addQuery('category', 'software');
inc.addQuery('priority', '1');
inc.setLimit(1); // Get just one record for the link
inc.query();
if (inc.next()) {
    var instanceUrl = gs.getProperty('glide.servlet.uri'); // Get the base URL of the instance
    gs.print('Link to Incident ' + inc.number + ': ' + instanceUrl + inc.getLink(false));
}
// Result: Returns the full URL to an incident record.

// Exercise 30: Using isValidRecord() - crucial for error checking after get()
var inc = new GlideRecord('incident');
inc.get('number', 'INC0010012'); // Try to fetch a specific incident
if (inc.isValidRecord()) {
    gs.print(inc.number + ' exists: ' + inc.isValidRecord());
} else {
    gs.print('Incident INC0010012 does not exist.');
}
// Result: Displays 'True' if the incident is found, 'False' otherwise.

Crafting Dynamic User Experiences: Exploring GlideForm (g_form)

While GlideRecord handles the backend heavy lifting, GlideForm (accessed via the global object g_form) is your command center for client-side form manipulation. It's the API you use when you want to make dynamic changes to a record's form directly in the user's browser. Think about scenarios like hiding a field based on another field's value, making a field mandatory, or displaying a custom message – that's g_form at play.

Since g_form methods run on the client-side, they're super fast and provide immediate feedback to the user without needing a server trip. This makes them indispensable for enhancing user experience and enforcing real-time validation. You'll frequently encounter g_form methods within Client Scripts, UI Policies, and even Catalog Client Scripts for Service Catalog items.

Key GlideForm Methods for UI Control

Here are some of the most used g_form methods:

  • setValue(fieldName, value): Sets the value of a form field.
  • getValue(fieldName): Retrieves the current value of a form field.
  • setMandatory(fieldName, boolean): Makes a field mandatory or optional.
  • setDisplay(fieldName, boolean): Hides or shows a field, occupying its space.
  • setVisible(fieldName, boolean): Hides or shows a field, removing its space (more common).
  • setReadOnly(fieldName, boolean) / setDisabled(fieldName, boolean): Makes a field read-only or editable.
  • addInfoMessage(message) / addErrorMessage(message): Displays messages to the user.
  • clearMessages(): Clears all current form messages.
  • flash(fieldName, color, count): Makes a field flash to draw attention.
  • showFieldMsg(fieldName, message, type) / hideFieldMsg(fieldName): Displays/hides field-specific messages.
  • getControl(fieldName): Returns the DOM element for a field (use sparingly, direct DOM manipulation can break with upgrades).
  • getTableName(): Returns the current table name.
  • getUniqueValue(): Returns the sys_id of the current record on the form.
  • isNewRecord(): Checks if the record on the form is new.
  • save() / submit(): Programmatically saves or submits the form.

GlideForm in Action: Hands-On with Incident Form

To try these out, navigate to an Incident record in your ServiceNow instance. Then, open your browser's developer console (usually F12 or Ctrl+Shift+J/Cmd+Option+J). In the console's JavaScript executor, you can type and execute these commands directly!

Getting and Setting Field Values

// Exercise 1: Working with getValue()
alert(g_form.getValue('category')); // Displays the current value of the 'Category' field in an alert box.
console.log(g_form.getValue('short_description')); // Prints the short description to the console.

// Exercise 2: Working with setValue()
g_form.setValue('category', 'hardware'); // Changes the 'Category' field to 'Hardware'.
// You'll see the field update instantly on the form.

Controlling Field Interactivity and Visibility

These methods are great for dynamic forms, but often UI Policies are a better, low-code alternative for simple conditions.

// Exercise 3: Working with setDisabled() (Makes a field read-only and greyed out)
g_form.setDisabled('category', true); // Makes the 'Category' field read-only.
// Note: While this works, for simple read-only requirements, UI Policies are often preferred as a no-code solution.

// Exercise 4: Working with setMandatory() (Makes a field required)
g_form.setMandatory('comments', true); // Makes the 'Comments' field mandatory.
// Note: Again, UI Policies are generally the best practice for mandatory fields based on conditions.

// Exercise 5: Working with setDisplay() (Hides/shows a field but retains its space)
g_form.setDisplay('business_service', false); // Hides the 'Business Service' field. The space it occupied remains.
// Note: UI Policies are a great low-code way to manage field visibility.

// Exercise 6: Working with setVisible() (Hides/shows a field and removes its space)
g_form.setVisible('subcategory', false); // Hides the 'Subcategory' field, collapsing its space. This is often more visually appealing.

Checking Field Properties

// Exercise 7: Working with isMandatory()
console.log('Is the Category field mandatory? ' + g_form.isMandatory('category'));
// Result: True or False, depending on current form configuration/scripts.

Troubleshooting Common Pitfalls and Debugging Tips

Even the most seasoned developers hit snags. Here's how to navigate some common issues with GlideRecord and GlideForm:

  • Missing query() or next(): A frequent mistake with GlideRecord is forgetting to call .query() after building your conditions, or forgetting .next() in your while loop. Without query(), your conditions aren't applied. Without next(), you're stuck on the first record (or none).
  • Incorrect Field Names: Typos in field names (e.g., shortdescription instead of short_description) are common. Always double-check schema definitions or field labels.
  • ACLs (Access Control Lists): Your script might fail to read, write, or create records even if the code is perfect. This is often an ACL issue. The user executing the script (or the system if it's a scheduled job) might not have the necessary permissions. ACLs are king!
  • Infinite Loops: If your server-side script runs indefinitely (e.g., while(true) without a breaking condition or a faulty inc.next()), it can lead to performance issues or even instance crashes. Be mindful of your loop conditions.
  • Client vs. Server Context: Remember which API belongs where. Using g_form on the server or GlideRecord directly on the client will result in errors.
  • Debugging Server-Side: Use gs.print() and gs.info() liberally in Script - Background or Business Rules. Check the System Logs (syslog.do) for output.
  • Debugging Client-Side: Use console.log() in your browser's developer console for client scripts. You can also set breakpoints to step through your code.
  • Encoded Queries: If an addEncodedQuery() isn't working, try building it in a list view first and copying the exact string. Ensure field names and operators are correct.
  • update() vs. updateMultiple(): Be acutely aware of the scope. update() affects only the current record in the loop. updateMultiple() affects all records matching the query *before* the loop. Use updateMultiple() with extreme caution, especially in production.

Acing Your Interview: What Interviewers Look For

GlideRecord and GlideForm are fundamental concepts, so expect questions about them in any ServiceNow developer or administrator interview. Here's what interviewers typically want to hear:

  • When to use Client-Side vs. Server-Side: Be able to articulate the difference and provide examples of when you'd use g_form (e.g., real-time validation, dynamic UI changes) versus GlideRecord (e.g., database updates, complex business logic, integrations).
  • getValue() vs. getDisplayValue(): Explain the difference clearly. getValue() gets the raw database value (sys_id for reference, integer for choice lists), while getDisplayValue() gets the user-friendly label. This is a classic interview question!
  • CRUD Operations: Demonstrate how to create, read, update, and delete records using GlideRecord. Talk about initialize(), insert(), addQuery(), query(), next(), update(), and deleteRecord().
  • Best Practices: Mention the importance of testing on non-production instances, handling ACLs, using encoded queries, and avoiding direct DOM manipulation.
  • Performance Considerations: Discuss limiting queries (setLimit()), optimizing filters, and minimizing unnecessary database calls.
  • Impact of autoSysFields(false) and setWorkflow(false): Explain what these do and the implications of using them (e.g., not triggering Business Rules, not updating 'sys_updated_on' fields). Interviewers want to know you understand the side effects.
  • Troubleshooting Skills: Be prepared to discuss how you would debug a GlideRecord script that isn't working as expected.

The key isn't just memorizing methods; it's understanding the "why" behind their use, their impact, and adhering to best practices.

Wrapping It Up: Your Journey to ServiceNow Scripting Mastery

Phew! We've covered a tremendous amount of ground today, diving deep into the essential world of GlideRecord and GlideForm in ServiceNow. You now have a solid understanding of how to interact with your instance's database on the server-side and manipulate form UIs on the client-side. From fetching specific incidents to dynamically changing fields and creating new records, these APIs are the bedrock of effective ServiceNow customization.

Remember, practice makes perfect. The more you experiment with these methods, the more intuitive they'll become. Keep the Script - Background and your browser's developer console open, try different scenarios, and don't be afraid to make mistakes – that's how we learn best. Embrace the power of scripting, and you'll transform your ServiceNow instance into a highly efficient, tailored platform. Happy scripting!


Scroll to Top