Dynamic Location Filtering in Catalog Item based on Requestor, Role, and Stockroom (cmn_location)

LavanyaB8479798
Tera Contributor

Hi All,

I am working on a ServiceNow catalog requirement where I need to dynamically filter a Location reference field based on multiple conditions like user role, requestor, hierarchy, and stockroom availability.


Scenario:

I have a Catalog Item with two Variable Sets:

  1. Variable Set 1

    • Field: Requestor For (Reference → sys_user)

  2. Variable Set 2

    • Field: Location (Reference → cmn_location)


🔹 Location Table Structure (cmn_location):

The hierarchy is as follows:

  • Region (e.g., APAC) → top level (parent is empty)

  • Country (e.g., India) → child of Region


🔹 Conditions:

I need to filter the Location field based on:

  1. Location attributes:

    • cmn_location_source = xxxxx

    • cmn_location_type = xxxx

  2. Stockroom condition:

    • Only locations that have a related record in alm_stockroom (i.e., location has a stockroom)

  3. User role:

    • If user has itil role → show Region level (APAC)

    • If user is end user → show Country level (India)

  4. Requestor-based filtering:

    • Based on selected Requestor For, restrict locations within the same hierarchy


🔹 What I Have Tried:

  • Created a Script Include (GlideAjax) to build dynamic query

  • Used Catalog Client Script (onChange) on Requestor For

  • Applied g_form.setReferenceQualifier() on Location field


🔹 Issue:

Since Requestor For and Location are in different variable sets,
I am unsure about the best approach to:

  • Trigger filtering correctly

  • Apply dynamic reference qualifier

  • Ensure it works across multiple catalog items


🔹 Questions:

  1. What is the best practice to handle filtering when variables are in different variable sets?

  2. Is GlideAjax + onChange the right approach, or can this be achieved using a reference qualifier?

  3. What is the optimal way to filter locations based on:

    • hierarchy (parent / parent.parent)

    • stockroom availability (alm_stockroom)

  4. How to make this reusable across multiple catalog items?


🔹 Any suggestions or best practices would be greatly appreciated.

Thanks in advance!

2 REPLIES 2

vaishali231
Tera Guru

hey @LavanyaB8479798 

 

 Approach 

1. Variable Sets do NOT block access

Even though Requestor For and Location are in different variable sets, they are still part of the same catalog item form.

So you can safely reference:

g_form.getValue('requestor_for');

No special handling is required just because they are in separate variable sets.

 

2. Use Advanced Reference Qualifier 

Instead of relying heavily on GlideAjax, the recommended approach is:

  • Use Advanced Reference Qualifier on the Location variable
  • Move all filtering logic into a Script Include

This keeps the solution:

  • Server-side
  • Performant
  • Reusable across catalog items

3. Centralize Logic in Script Include

Create a Script Include (non-client callable) that builds the encoded query.

Code:

var LocationFilterUtil = Class.create();
LocationFilterUtil.prototype = {
   getLocationQuery: function(requestorId) {
       var query = [];
       // Base filters
       query.push("cmn_location_source=xxxxx");
       query.push("cmn_location_type=xxxx");
       // Stockroom condition (only locations with stockroom)
       var locs = [];
       var ga = new GlideAggregate('alm_stockroom');
       ga.groupBy('location');
       ga.query();
       while (ga.next()) {
           locs.push(ga.location.toString());
       }
       if (locs.length)
           query.push("sys_idIN" + locs.join(','));
       // Requestor-based filtering
       if (requestorId) {
           var user = new GlideRecord('sys_user');
           if (user.get(requestorId) && user.location) {
               query.push("parent=" + user.location); // adjust if hierarchy differs
           }
       }
       // Role-based filtering
       if (gs.hasRole('itil')) {
           query.push("parentISEMPTY"); // Region level
       } else {
           query.push("parentISNOTEMPTY"); // Country level
       }
       return query.join('^');
   },
   type: 'LocationFilterUtil'

};

4. Apply in Reference Qualifier

On the Location variable:

javascript: new LocationFilterUtil().getLocationQuery(current.variables.requestor_for);

5. Handle Dynamic Changes (onChange)

If Requestor For can change after load, add a Catalog Client Script:

function onChange(control, oldValue, newValue, isLoading, isTemplate) {
   if (isLoading || newValue === '') {
      return;
   }
   g_form.setValue('location', '');
   g_form.refreshReference('location');

}

This ensures the Location field refreshes with updated filters.

*************************************************************************************************************************************

If this response helps, please mark it as Accept as Solution and Helpful.

Doing so helps others in the community and encourages me to keep contributing.

Regards

Vaishali Singh




Even after applying all conditions, I am still getting:

  • Locations from other countries (e.g., United States)

  • Locations not related to the requestor’s location (e.g., India)

Expected:

  • ✔ Only locations under requestor’s hierarchy

  • ✔ Only stockroom-related locations


Example:

  • Requestor Location → India

  • Expected → Only India child locations (sites with stockroom)

  • Actual → Getting locations from other regions as well