Auto-populate List Collector field based on another field selection in Catalog Item

aparnaravi
Tera Contributor

Hi all

In our Service Catalog item, we have a variable called Select the Application and another variable called Notify Additional User, which is a List Collector.

We have a requirement that
when the user selects Concur in the Select the Application field,
the Notify Additional User field should automatically populate with a specific set of users.

I tried using a Catalog Client Script + Script Include (Client Callable) approach to set values using g_form.setValue() and GlideAjax, but it didn’t work.

The Notify Additional User field is a List Collector type variable, so maybe setValue() doesn’t work directly.

Has anyone implemented a similar scenario
How can I auto-populate the List Collector field with multiple users based on the selected application value

Any help or example script would be appreciated. šŸ™

3 REPLIES 3

mayankkumar
Kilo Patron
Kilo Patron

Hi @aparnaravi,
If you're using the setValue in the client script, try adding the "glide_list" variable attribute in your list collector variable
------------------------------------------------------------------------------------------------------------------------------------
Please mark my response helpful and accept as solution
Thanks & Regards
Mayank
Rising Star 2025

MaxMixali
Giga Guru

ServiceNow – Service Catalog: Auto-populate a List Collector (Notify Additional User) based on 'Select the Application'

Use Case
In a Catalog Item, when the user selects a specific application (e.g., 'Concur') in variable 'Select the Application', you want to auto-populate a List Collector variable 'Notify Additional User' with a predefined set of users. The List Collector should show those users already selected without manual action.

Key Points (List Collector Behavior)
- A Service Catalog List Collector stores its selection as a COMMA-SEPARATED LIST of sys_ids.
- You can set it with: g_form.setValue('<list_collector_name>', 'sysid1,sysid2,sysid3');
- After setting the value, call: g_form.refreshSlushbucket('<list_collector_name>') to refresh the dual-list UI.
- Always use the variable *Name* (not the Label) in client scripts.

Recommended Pattern
1) OnChange Catalog Client Script on 'Select the Application'.
2) Use GlideAjax to fetch the correct user sys_ids for the selected application.
3) In the callback, set the list collector value to a comma-separated string and refresh the slushbucket.

A) Catalog Client Script (onChange on 'Select the Application')
Type: onChange
Applies to: Catalog Items
UI Type: All (or Desktop as needed)

function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading) return;
// Replace with your variable names
var VAR_APP = 'select_the_application';
var VAR_USERS = 'notify_additional_user';

// Reset when empty or not Concur
if (!newValue) {
g_form.setValue(VAR_USERS, '');
g_form.refreshSlushbucket(VAR_USERS);
return;
}

// If you need to target only Concur by name, compare display value:
// var disp = g_form.getDisplayBox(VAR_APP).value; // display text (if reference or select)
// if (disp !== 'Concur') { ... }

var ga = new GlideAjax('SCNotifyDefaults');
ga.addParam('sysparm_name', 'getDefaultUsersForApp');
ga.addParam('sysparm_app', newValue); // pass selected app value (sys_id or choice value)
ga.getXMLAnswer(function(ans) {
// ans should be 'sysid1,sysid2,sysid3' or '' if none
if (typeof ans === 'string') {
g_form.setValue(VAR_USERS, ans);
g_form.refreshSlushbucket(VAR_USERS);
} else {
g_form.setValue(VAR_USERS, '');
g_form.refreshSlushbucket(VAR_USERS);
}
});
}

Notes:
- If 'Select the Application' is a *reference* to an Application table, newValue is a sys_id. If it's a *select/choice*, it's the choice value. Adjust server query accordingly.
- If you only want this logic for 'Concur', check the display value OR map by the sys_id of Concur for reliability.

B) Script Include (Client Callable) – Return comma-separated sys_ids
Name: SCNotifyDefaults
Client Callable: true

var SCNotifyDefaults = Class.create();
SCNotifyDefaults.prototype = Object.extendsObject(AbstractAjaxProcessor, {
getDefaultUsersForApp: function() {
var appIdOrValue = (this.getParameter('sysparm_app') || '').toString();
if (!appIdOrValue) return '';

// OPTION 1: Use a mapping table (recommended for maintainability)
// Table: u_app_notify_defaults (u_application REF, u_user REF, active TRUE/FALSE)
var users = [];
var map = new GlideRecord('u_app_notify_defaults');
map.addActiveQuery();
// If 'Select the Application' is a REFERENCE, compare to a reference field
map.addQuery('u_application', appIdOrValue);
// If it's a CHOICE field instead, use name/value lookups here (adjust accordingly)
map.query();
while (map.next()) {
if (map.u_user) users.push(map.u_user.toString());
}
return users.join(',');

// OPTION 2: Hardcode by Application (quick approach)
/*
var out = [];
// 'Concur' sys_id or value; replace 'YOUR_CONCUR_SYS_ID' with actual id/value
if (appIdOrValue === 'YOUR_CONCUR_SYS_ID_OR_VALUE') {
out = ['USER_SYS_ID_1','USER_SYS_ID_2','USER_SYS_ID_3'];
}
return out.join(',');
*/
},

isPublic: function() { return true; }
});

C) Variable Configuration Checklist
- 'Notify Additional User' (List Collector):
• List table: sys_user
• Reference qualifier: ensure it does NOT exclude your default users. If necessary, adjust ref qual to include them.
• Name: notify_additional_user (use this in scripts)

- 'Select the Application':
• If it's a reference, newValue in client script is the sys_id.
• If it's a choice, newValue is the choice value. You might need to look up the App record or maintain a mapping table keyed by value.

D) Common Pitfalls & Fixes
1) Using setValue with display names -> WRONG. Use sys_ids, comma-separated.
2) Not refreshing slushbucket -> the UI won’t display selections until g_form.refreshSlushbucket() is called.
3) Using variable Label instead of Name -> scripts fail silently.
4) Ref Qual removes your preselected users -> ensure your qualifier includes them.
5) Client script not running -> make sure 'Applies to' includes the Catalog Item and the UI policy doesn’t make the field read-only until after population.
6) Mobile vs Desktop -> If using Mobile, confirm UI Type includes Mobile or use a different approach.

E) Optional: Lock the defaults for 'Concur'
If you want the selection to be read-only when Concur is chosen:
- After setting the values, call: g_form.setReadOnly('notify_additional_user', true);
- On other apps, set it back to false.

F) Server-Only Alternative (No Client Script)
- Use a 'Run script' step in Flow Designer (on request submitted) or a Before Insert Business Rule on sc_req_item to set RITM variables programmatically:
var ritm = new GlideRecord('sc_req_item'); ...
ritm.variables.notify_additional_user = 'sysid1,sysid2,sysid3';
- This guarantees persistence even if the client script fails, but won’t show the preselection during form fill.

TL;DR
- Return a comma-separated list of user sys_ids for the selected app via GlideAjax.
- Set the List Collector value with g_form.setValue('<name>', 'id1,id2,id3') and then call g_form.refreshSlushbucket('<name>').
- Maintain the mapping in a small table (u_app_notify_defaults) or hardcode IDs initially.

MaxMixali
Giga Guru

ServiceNow – Auto‑populate a List Collector (Notify Additional User) based on ā€œSelect the Applicationā€

Goal
When the requester selects ā€œConcurā€ in the catalog variable ā€œSelect the Applicationā€, auto‑populate the List Collector variable ā€œNotify Additional Userā€ with a predefined set of users (multiple sys_ids).

Key points about List Collectors
- They accept a comma‑separated list of sys_ids.
- After setting the value, call: g_form.refreshSlushbucket('variable_name') so the UI updates.
- Use an onChange Catalog Client Script on the driving variable (ā€œSelect the Applicationā€).
- Get the target users via GlideAjax (client‑callable Script Include) or a simple mapping table.
- Clear/reset when the selection is not Concur.

A. Catalog Client Script (onChange on ā€œSelect the Applicationā€)
Type: onChange | Applies to: Catalog Client Script | UI Type: All
Variable name example:
- Select the Application → var name: application (reference to some app table or select box)
- Notify Additional User (List Collector) → var name: notify_additional_user (reference = sys_user)

Script:
function onChange(control, oldValue, newValue, isLoading) {
if (isLoading) return;

// Adjust these to your variable names
var VAR_APP = 'application';
var VAR_LC = 'notify_additional_user';

// If cleared or not Concur, reset list collector and exit
if (!newValue) {
g_form.setValue(VAR_LC, '');
if (g_form.refreshSlushbucket) g_form.refreshSlushbucket(VAR_LC);
return;
}

// Normalize and check for Concur (depending on how your app variable stores value)
// If it's a select box with text values, compare display. If it's a reference, compare sys_id or displayValue.
var isConcur = false;

// Example 1: application is a select box storing text "Concur"
var selectedText = g_form.getDisplayBox(VAR_APP) ? g_form.getDisplayBox(VAR_APP).value : '';
if ((selectedText || '').toLowerCase() === 'concur') isConcur = true;

// Example 2 (uncomment if 'application' is a reference): check display value
// var appDisplay = g_form.getDisplayValue(VAR_APP) || '';
// if (appDisplay.toLowerCase() === 'concur') isConcur = true;

if (!isConcur) {
g_form.setValue(VAR_LC, '');
if (g_form.refreshSlushbucket) g_form.refreshSlushbucket(VAR_LC);
return;
}

// Fetch default users for Concur via GlideAjax
var ga = new GlideAjax('CatalogNotifyDefaults');
ga.addParam('sysparm_name', 'getUsersForApp');
ga.addParam('sysparm_app', 'Concur'); // or pass newValue/sys_id if your mapping uses ids
ga.getXMLAnswer(function(ans) {
// Expect a comma-separated list of sys_ids or empty string
if (ans) {
g_form.setValue(VAR_LC, ans);
if (g_form.refreshSlushbucket) g_form.refreshSlushbucket(VAR_LC);
} else {
g_form.setValue(VAR_LC, '');
if (g_form.refreshSlushbucket) g_form.refreshSlushbucket(VAR_LC);
}
});
}

B. Client‑callable Script Include (returns sys_ids)
Name: CatalogNotifyDefaults | Accessible from: Global or your app scope | Client callable: true

var CatalogNotifyDefaults = Class.create();
CatalogNotifyDefaults.prototype = Object.extendsObject(AbstractAjaxProcessor, {
getUsersForApp: function() {
// Input can be app display or sys_id; adjust logic as needed
var app = (this.getParameter('sysparm_app') || '').toString().toLowerCase();

// Option 1: Hardcoded mapping (quick start)
var MAP = {
'concur': [
'681bf843c0a8016400b98a06818d57c7', // example sys_id
'46d44a40c0a8010e01b93d1e6bba8f4a'
]
};
if (MAP[app]) return MAP[app].join(',');

// Option 2: Dynamic from a small table (recommended for maintainability)
// Table: u_app_notify_defaults (fields: u_app_name, u_user reference: sys_user, u_active)
var ids = [];
var gr = new GlideRecord('u_app_notify_defaults');
gr.addQuery('u_active', true);
gr.addQuery('u_app_name', 'CONTAINS', app); // or '=' if you store exact names
gr.query();
while (gr.next()) {
if (gr.u_user) ids.push(gr.u_user.toString());
}
return ids.join(',');
},

isPublic: function() { return true; }
});

C. Common pitfalls & checks
1) Variable names: Use the **variable name**, not the label (e.g., notify_additional_user).
2) List Collector reference: The slushbucket must reference **sys_user** (or a table compatible with your ids).
3) Refresh UI: Always call **g_form.refreshSlushbucket('notify_additional_user')** after setValue.
4) Reference qualifiers: Ensure the list collector’s ref qual doesn’t exclude your default users.
5) Workspace/EC: If using Employee Center / Workspace, set **UI Type = All** and enable **Compatibility Mode** on the form if needed.
6) Read‑only after populate (optional): Use a Catalog UI Policy to set the list collector read‑only when app = Concur (so defaults aren’t removed).
7) OnLoad default (optional): Duplicate the logic in an **onLoad** script to pre‑fill Concur if the item opens with that value.

D. Minimal ā€œhardcodedā€ working demo
- Replace the two example sys_ids with real user sys_ids from your instance.
- Paste the onChange script and Script Include, test the flow:
- Change app to Concur → List Collector fills with your users
- Change app away from Concur → List Collector clears

E. Alternative: No GlideAjax (pure client) using a JSON map
If the mapping is small and static, you can keep it client‑side:
var DEFAULTS = {'concur': 'id1,id2,id3'};
if (DEFAULTS[app]) {
g_form.setValue('notify_additional_user', DEFAULTS[app]);
g_form.refreshSlushbucket('notify_additional_user');
}

Summary
- List Collectors can be programmatically set with a comma‑separated list of user sys_ids.
- After setting, call refreshSlushbucket to update the dual list UI.
- Use onChange + GlideAjax to fetch the right ids for the selected application (ā€œConcurā€), and clear when not applicable.