GlideForm APIs: Your Guide to Interactive ServiceNow Forms






Mastering GlideForm APIs: A Deep Dive into ServiceNow Client-Side Development


Mastering GlideForm APIs: A Deep Dive into ServiceNow Client-Side Development

In the world of ServiceNow development, the ability to dynamically manipulate forms and user experiences is crucial. This is where the GlideForm API shines. Whether you’re a seasoned developer or just starting your journey, understanding how to effectively use GlideForm is fundamental to building intuitive and efficient applications. This article will take you on a comprehensive tour of GlideForm, exploring its core components, practical applications, and some advanced techniques to elevate your ServiceNow game.

Quick Note: The GlideForm API primarily operates on the client-side. This means it executes in the user’s browser, allowing for immediate feedback and interactive form changes without requiring a server round trip.

Understanding the Core: Getting User Information

A common requirement in ServiceNow is to personalize the user experience by leveraging information about the currently logged-in user. GlideForm provides straightforward ways to access this data.

Getting the Current Logged-In User’s System ID (Client-Side)

When you need to reference the unique system identifier (sys_id) of the current user within a client-side script (like a UI Policy script or a client script), the g_user object is your go-to. Specifically, the g_user.userID property holds this valuable piece of information.

// Example: Setting a field with the current user's sys_id
    g_form.setValue('requested_for', g_user.userID);

This is incredibly useful for pre-populating fields, assigning tasks, or performing other actions that depend on the current user’s identity. For instance, if you have a ‘Requested For’ field, you might automatically set it to the current user when a new record is created.

Getting the Current Logged-In User’s System ID (Server-Side)

While this article focuses on GlideForm (client-side), it’s worth noting the server-side equivalent for completeness. On the server, you’d use the gs.getUserID() method. This distinction is important, as mixing client-side and server-side scripting can lead to unexpected behavior.

// Example: Server-side code to get user ID
    var currentUserID = gs.getUserID();

Controlling Field Behavior: Mandatory, Read-Only, and More

One of the primary functions of GlideForm is to dynamically control the behavior and visibility of form fields. This makes forms more intuitive and guides users through complex processes.

Ways to Make a Field Mandatory or Read-Only

ServiceNow offers a robust set of tools for enforcing data integrity and controlling user input. You can make a field mandatory or read-only through several mechanisms:

  • Dictionary Properties: The most fundamental level, defined directly on the field’s definition.
  • Dictionary Overrides: Allows you to modify dictionary properties for specific tables without altering the base definition.
  • UI Policies: Client-side logic that dynamically changes form attributes (like mandatory, read-only, visible) based on conditions. This is where g_form plays a significant role.
  • Data Policies: Similar to UI Policies, but these enforce data integrity at the server-side (and can also have client-side effects).
  • g_form.setMandatory(fieldName, boolean): A direct client-side method within scripts to set a field’s mandatory status.

g_form.setMandatory(script) in Action

When you need fine-grained control that goes beyond simple UI Policies, client scripts using g_form.setMandatory() are invaluable. This allows you to make a field mandatory or optional based on complex logic.

// Example: Make 'assignment_group' mandatory only if 'state' is not 'Closed'
    function onChange(control, oldValue, newValue, isLoading, isTemplate) {
        if (isLoading || newValue === '') {
            return;
        }

        if (newValue === 'closed') {
            g_form.setMandatory('assignment_group', false); // Make it optional
        } else {
            g_form.setMandatory('assignment_group', true);  // Make it mandatory
        }
    }

This example demonstrates how to dynamically control the mandatory status of the ‘assignment_group’ field based on the ‘state’ field’s value.

The ‘current’ Object: Server-Side Form Manipulation

While GlideForm (g_form) is for client-side interactions, the current object is its server-side counterpart. It represents the record being accessed or manipulated.

What is the ‘current’ Object?

The current object in server-side scripts (like Business Rules or Script Includes) is an instance of the table record you are currently working with. It’s used to retrieve and set values on that specific record.

Setting Field Values on the Server-Side (using ‘current’)

When working with the current object, you have two primary methods for setting field values:

  • current.setValue('field_name', value): This method sets the actual value of the field. For reference fields, you must provide the sys_id of the referenced record as the value.
  • current.setDisplayValue('field_name', value): This method sets the display value of a field. For reference fields, you can provide the actual display name (e.g., “John Doe”) instead of the sys_id. ServiceNow will then attempt to resolve this display value to the correct sys_id.

Practical Example:

Imagine a Business Rule that runs when an Incident is assigned to a new group. You want to automatically set the ‘assigned_to’ field to the first user in that group.

// Business Rule Script (after insert/update)
    if (current.assignment_group.changes() && !current.assignment_group.nil()) {
        var group = current.assignment_group.getRefRecord();
        var grUser = new GlideRecord('sys_user_group');
        if (grUser.get(group.getUniqueValue())) {
            var firstUserSysId = '';
            var userQuery = new GlideRecord('sys_user');
            userQuery.addQuery('sys_id', 'IN', grUser.user.toString()); // Assuming users are directly linked to group
            userQuery.query();
            if (userQuery.next()) {
                firstUserSysId = userQuery.getUniqueValue();
            }

            if (firstUserSysId) {
                current.setValue('assigned_to', firstUserSysId);
            }
        }
    }

Here, current.setValue('assigned_to', firstUserSysId) is used to set the reference field with the sys_id.

Key Takeaway: Use setValue with sys_ids for reference fields when you have the exact identifier. Use setDisplayValue when you have the display name and want ServiceNow to perform the lookup (though this can be less performant and prone to errors if names aren’t unique).

Refining Reference Fields: Reference Qualifiers

Reference fields are powerful for linking records, but without proper filtering, they can become overwhelming. Reference Qualifiers are the solution, allowing you to restrict the options presented to the user.

What are Reference Qualifiers?

Reference Qualifiers are used to filter the records that appear in reference and list type fields. They act as dynamic filters, ensuring users select relevant records, thus improving data accuracy and user experience.

Types of Reference Qualifiers

There are three main types of Reference Qualifiers, each offering a different level of complexity and flexibility:

1. Simple Reference Qualifier

Description: This is the most straightforward type, where you define a static query using dot-walking or direct field conditions to filter the referenced records.

Example: On an Incident form, you might have a ‘Business Service’ reference field. You could use a simple reference qualifier to show only “Active” Business Services.

How to Use: In the dictionary entry of the reference field, under the ‘Reference Qualificatiions’ section, select ‘Simple’ and enter your query conditions.

// Example condition in the Reference Qualifier field:
    active=true^support_group.name=IT^ORsupport_group.name=Help Desk

This qualifier would display business services that are active and are supported by either the ‘IT’ or ‘Help Desk’ support group.

2. Dynamic Reference Qualifier

Description: This type leverages pre-defined ‘Dynamic Filter Options’ to create context-aware filters. These options can be reused across multiple reference fields and can adapt based on the current record’s data.

Example: On an Incident form, you might want to filter the ‘Affected CI’ field to only show Configuration Items (CIs) that belong to the same ‘Configuration Item Category’ as the selected ‘Business Service’.

How to Use:

  1. Navigate to System Definition > Dynamic Filter Options.
  2. Create a new Dynamic Filter Option, defining the conditions.
  3. In the dictionary entry of your reference field, under ‘Reference Qualificatiions’, select ‘Dynamic’ and choose your created Dynamic Filter Option.

Dynamic Filter Options are powerful for creating reusable and context-sensitive filtering logic without extensive scripting.

3. Advanced Reference Qualifier (JavaScript Reference Qualifier)

Description: This is the most powerful and flexible option, allowing you to write custom JavaScript code to define complex filtering logic. This is ideal for scenarios where the filtering criteria are highly dynamic and depend on multiple form fields or complex business rules.

Example: Filtering a ‘Related Incidents’ reference field on the Incident form to show only incidents that are assigned to the current user’s assignment group, have a priority less than ‘High’, and are not the current incident itself.

How to Use: In the dictionary entry of the reference field, under ‘Reference Qualificatiions’, select ‘Advanced’ and enter your JavaScript code. The script should return a query string.

// Example JavaScript in the Advanced Reference Qualifier field:
    javascript: 'assignment_group=' + g_form.getValue('assignment_group') + '^priority<3^sys_id!=' + g_form.getUniqueValue();

In this example:

  • g_form.getValue('assignment_group') dynamically retrieves the assignment group from the current form.
  • ^priority<3 filters for incidents with a priority less than 3 (e.g., Critical, High).
  • ^sys_id!=' + g_form.getUniqueValue() excludes the current incident from the results.

Reference Qualifier Differences Explained:

  • Simple vs. Dynamic: Simple qualifiers use fixed conditions, while dynamic ones use pre-defined, reusable filter options that adapt to context.
  • Dynamic vs. Advanced: Dynamic qualifiers are declarative and rely on pre-configured filter options. Advanced qualifiers require custom JavaScript for maximum flexibility.
  • Simple vs. Advanced: Simple qualifiers are for basic, static filtering. Advanced qualifiers are for complex, dynamic filtering that requires scripting.
Troubleshooting Reference Qualifiers:

  • Field is empty: Double-check your syntax, especially for dot-walking and AND/OR conditions. Ensure the referenced records actually exist and meet the criteria.
  • Incorrect records displayed: Verify that the correct fields are being queried and that the logic accurately reflects your requirements. For advanced qualifiers, use gs.log() (server-side) or console.log() (client-side) within your script to debug.
  • Performance issues: Complex dot-walking in simple qualifiers or overly broad queries in advanced qualifiers can slow down forms. Optimize your queries.

Dependent Values: Cascading Select Boxes

Dependent values are essential for creating structured data entry, commonly seen in cascading dropdown menus. They ensure that the choices in one field are filtered based on the selection in another parent field.

What are Dependent Values?

In ServiceNow’s dictionary, dependent values are configured to filter the available choices in a field (the dependent field) based on the selection made in another field (the parent field). This is most frequently used for creating hierarchical selections, like Category and Subcategory.

Steps to Configure Dependent Values

  1. Identify Parent and Dependent Fields: Determine which field will control the other. For example, ‘Category’ (parent) and ‘Subcategory’ (dependent).
  2. Configure the Parent Field: Ensure the parent field has a defined set of choices (e.g., Hardware, Software, Network for ‘Category’).
  3. Configure the Dependent Field:
    • Navigate to the dictionary entry for the dependent field (e.g., ‘Subcategory’).
    • In the ‘Dependent field’ attribute, specify the name of the parent field (e.g., category).
    • For each choice in the dependent field, link it to a specific value of the parent field. This is done by defining the ‘dependent_value’ attribute for each choice.

Example: Category and Subcategory

Parent Field: category (Table: incident)
Choices:

  • Hardware
  • Software
  • Network

Dependent Field: subcategory (Table: incident)

Dictionary Entry for ‘subcategory’:

  • Dependent field: category

Choices for ‘subcategory’:

  • Label: Laptop, Value: laptop, Dependent value: Hardware
  • Label: Desktop, Value: desktop, Dependent value: Hardware
  • Label: Printer, Value: printer, Dependent value: Hardware
  • Label: Operating System, Value: os, Dependent value: Software
  • Label: Application, Value: app, Dependent value: Software
  • Label: Database, Value: db, Dependent value: Software
  • Label: Router, Value: router, Dependent value: Network
  • Label: Switch, Value: switch, Dependent value: Network
  • Label: Firewall, Value: firewall, Dependent value: Network

With this configuration, selecting “Hardware” for Category will only show Laptop, Desktop, and Printer in the Subcategory dropdown.

Calculated Values: Deriving Field Values Programmatically

Sometimes, a field’s value isn’t directly entered but is instead calculated based on other fields. The Dictionary Property for calculated values is designed for this purpose.

What is a Calculated Value?

If you want to automatically compute a field’s value based on other field values using the current object (on the server-side), you can define a “Calculated” type for the field in its dictionary entry. This allows you to embed a script that will execute to determine the field’s value.

How to Use:

  1. Go to the dictionary entry of the field you want to make calculated.
  2. Set the Type to Calculated.
  3. In the Calculation script field, write your JavaScript code. This script should return the desired value.
// Example: Calculate 'Total Price' based on 'Quantity' and 'Unit Price'
    // Dictionary Entry for 'total_price' field, Type: Calculated
    // Calculation Script:
    var quantity = current.quantity;
    var unitPrice = current.u_unit_price; // Assuming a custom field for unit price

    if (quantity && unitPrice) {
        return quantity * unitPrice;
    }
    return 0; // Default if values are missing

This calculation will run whenever the record is saved or when the relevant fields (‘quantity’ or ‘u_unit_price’) change, ensuring the ‘total_price’ is always up-to-date.

Server-Side Execution: Calculated fields are evaluated on the server-side. This means they are not dynamically updated in real-time as the user types unless a server-side event (like saving or updating) is triggered.

UI Policies: Dynamic Client-Side Form Behavior

UI Policies are a cornerstone of client-side form customization in ServiceNow. They provide a no-code/low-code way to control field visibility, mandatory status, read-only properties, and more.

What are UI Policies?

UI Policies are used to make fields mandatory, read-only, visible/invisible, or to show/hide related lists based on specific conditions. They execute on the client-side, offering immediate feedback to the user as they interact with the form.

Key UI Policy Attributes Explained

  • Global Checkbox:

    When checked, the UI Policy will apply to all views of the form. If unchecked, you’ll be prompted to specify the views where the UI Policy should be active. This is crucial for controlling form behavior across different user interfaces or customized views.

  • Reverse if False:

    If this checkbox is selected, the actions defined in the UI Policy will be reversed when the condition evaluates to false. For instance, if a field is made mandatory when the condition is true, it will become optional again when the condition is false. This is incredibly useful for toggling states.

  • On Load Checkbox:

    When checked, the UI Policy’s conditions and actions are evaluated and applied as soon as the form loads. If unchecked, the UI Policy actions will only trigger when a specific field’s value changes or when another condition is met on the form, making it more reactive.

  • Inherit Checkbox:

    When this checkbox is checked, the UI Policy will also be applied to child tables that extend the table on which the UI Policy is defined. This is a powerful way to enforce consistent behavior across table hierarchies.

Can You Write Scripts in UI Policies?

Yes! While UI Policies are often associated with no-code configuration, they offer scripting capabilities for more complex scenarios. To do this:

  1. Enable the Run Scripts checkbox on the UI Policy record.
  2. Within the UI Policy Actions, enable the Run script checkbox for specific actions. This allows you to enter client-side JavaScript that will execute when the UI Policy’s conditions are met.

This combination of declarative conditions and custom scripting provides immense power and flexibility in controlling form behavior.

Converting UI Policies to Data Policies

ServiceNow provides a convenient feature to convert UI Policies into Data Policies. This is useful when you want to enforce the same logic on both the client and server side.

How to Convert: Open the UI Policy record and look for a button or related link that says “Convert this UI Policy to a Data Policy” (or similar wording). Clicking this will create a corresponding Data Policy record.

When UI Policies Cannot Be Converted to Data Policies

While the conversion is often seamless, there are specific scenarios where a UI Policy’s functionality cannot be directly translated into a Data Policy:

  • Controlling Data Visibility: UI Policies can hide fields or entire sections of a form based on client-side conditions. Data Policies operate on data integrity and cannot directly control what the user sees on the form in the same way.
  • Controlling Views: UI Policies might be configured to apply only to specific views. Data Policies are view-agnostic.
  • Controlling Related Lists: UI Policies can show or hide related lists dynamically. Data Policies focus on record data, not the layout of related lists.
  • Controlling Scripts: If a UI Policy relies heavily on complex client-side scripting for its actions (beyond simple field manipulations), converting it directly to a Data Policy might not be feasible without significant refactoring.

Data Policies: Server-Side Data Integrity

Data Policies are the server-side counterpart to UI Policies, ensuring that data integrity rules are enforced regardless of how the data is entered (e.g., via forms, integrations, or imports).

What are Data Policies?

Data Policies are used to make fields mandatory, read-only, or visible based on certain conditions. Crucially, they operate at the data level, meaning they are enforced on the server-side. This guarantees data consistency across all data sources.

Key Benefits:

  • Data Integrity: Enforces rules consistently, whether data comes from a form, an import set, or an API call.
  • Performance: While they have client-side effects (if the “Use as UI Policy on client” checkbox is checked), their primary strength is server-side enforcement, reducing the reliance on client-side scripts for critical validation.
  • Reduced Redundancy: Avoids duplicating validation logic in multiple Business Rules.
Interview Relevance: Understanding the differences and use cases for UI Policies vs. Data Policies is a common interview topic for ServiceNow developers. Be prepared to explain when to use each and the implications of their client-side vs. server-side execution.

Putting It All Together: A Practical Scenario

Let’s consider a common scenario: creating a service request form where the user selects a service, and based on that service, a specific support group and a default assignment rule should be applied.

Requirements:

  • User selects a ‘Service’ from a reference field.
  • Based on the ‘Service’, the ‘Assignment Group’ field should be populated.
  • The ‘Assignment Group’ should be mandatory if the ‘State’ is not ‘Closed’.

Implementation:

  1. Service Dictionary: Ensure your ‘Service’ reference field is correctly configured.
  2. Assignment Group Dictionary: Ensure the ‘Assignment Group’ field is a reference to the ‘sys_user_group’ table.
  3. UI Policy:
    • Name: Set Assignment Group based on Service
    • Table: Incident (or your relevant table)
    • Short description: Set Assignment Group based on selected Service.
    • Conditions: None (we’ll use scripts for dynamic logic).
    • Run Scripts: Checked.
    • On Load: Checked.
    • UI Policy Actions:
      • Field: Assignment Group
      • Visible: True
      • Mandatory: True
      • Read only: False
    • Script (In UI Policy): This is where we’ll handle the dynamic assignment.
  4. Client Script (onChange for ‘Service’ field): This script will trigger when the ‘Service’ field changes.
    function onChange(control, oldValue, newValue, isLoading, isTemplate) {
                    if (isLoading || newValue === '') {
                        return;
                    }
    
                    var serviceSysId = newValue;
                    var assignmentGroup = g_form.getValue('assignment_group'); // Get current value
    
                    // AJAX call to get the default assignment group for the service
                    var ga = new GlideAjax('ServiceUtils'); // Assuming a Script Include named ServiceUtils
                    ga.addParam('sysparm_name', 'getDefaultAssignmentGroup');
                    ga.addParam('sysparm_service_sysid', serviceSysId);
                    ga.getXMLAnswer(function(answer) {
                        if (answer) {
                            g_form.setValue('assignment_group', answer);
                            // Now, enforce mandatory based on state, potentially triggering the UI policy again
                            setMandatoryAssignmentGroup();
                        } else {
                            g_form.setValue('assignment_group', ''); // Clear if no group found
                            setMandatoryAssignmentGroup();
                        }
                    });
    
                    // Function to handle mandatory status based on state
                    function setMandatoryAssignmentGroup() {
                        var state = g_form.getValue('state');
                        if (state !== '7') { // Assuming '7' is the sys_id for 'Closed' state
                            g_form.setMandatory('assignment_group', true);
                        } else {
                            g_form.setMandatory('assignment_group', false);
                        }
                    }
    
                    // Trigger mandatory check on load as well
                    setMandatoryAssignmentGroup();
                }
  5. Script Include (ServiceUtils):
    var ServiceUtils = Class.create();
                ServiceUtils.prototype = Object.extend(new global.AbstractAjaxProcessor(), {
    
                    getDefaultAssignmentGroup: function() {
                        var serviceSysId = this.getParameter('sysparm_service_sysid');
                        var defaultGroupSysId = '';
    
                        var grService = new GlideRecord('cmdb_ci_service'); // Or your service table
                        if (grService.get(serviceSysId)) {
                            // Assuming you have a reference field on the Service table called 'default_assignment_group'
                            defaultGroupSysId = grService.getValue('default_assignment_group');
                        }
                        return defaultGroupSysId;
                    },
    
                    type: 'ServiceUtils'
                });
  6. UI Policy (for mandatory ‘assignment_group’):
    • Name: Make Assignment Group Mandatory if not Closed
    • Table: Incident
    • Short description: Make Assignment Group mandatory unless state is Closed.
    • Conditions: State | is not | Closed
    • Reverse if False: True
    • UI Policy Actions:
      • Field: Assignment Group
      • Visible: True
      • Mandatory: True
      • Read only: False

This comprehensive approach uses a client script to trigger an AJAX call to a Script Include, which fetches the correct assignment group. The client script then uses g_form.setValue() to update the field. A separate UI Policy handles the mandatory logic based on the state. This demonstrates how different ServiceNow tools work in conjunction to create dynamic and user-friendly forms.

Conclusion

The GlideForm API, alongside its server-side counterparts and related features like UI Policies and Data Policies, provides a powerful toolkit for crafting dynamic and responsive ServiceNow applications. By mastering these concepts, you can significantly enhance user experience, improve data accuracy, and build more sophisticated business solutions. Remember to always consider the client-side vs. server-side implications of your scripts and choose the right tool for the job. Happy coding!


Scroll to Top