I often encounter two distinct but related scenarios where I either need to change a reference qualifier on a variable in a single-row variable set, but only for a certain catalog item, or I cannot set a reference qualifier to what I want (what I really, really want) in a multi-row variable set variable that relieson the value of a catalog item variable. This article presents two examples, then details surprisingly simple solutions to both.
Scene 1: "A Change Will Do You Good"
A popular variable is part of an established single-row variable set that has been added to many catalog items over time. This variable is a reference with a qualifier, controlling what can be seen - and not seen - in a list of records. A new catalog item comes along and challenges the status quo. It includes the variable set for efficiency, but wants the reference variable to change its ways. The reference variable reluctantly accepts that its qualifier needs to change - but only for this one item (so far). How can this be done? Read on!
Starting Point: Common workarounds to this scenario are to either not use the variable set, necessitating the re-creation of all the variables for this rogue catalog item (and any that follow with a similar use case), or to create one variable with the new reference qualifier in the catalog item or within the variable set, then hide the original variable on the new catalog item.
Conflict: The biggest downside common to both workarounds, aside from creating one or more extra variables, is that to maintain downstream usage and reporting on the variable across catalog items, the value from the new variable needs to be copied to the old one, then kept in sync or hidden...
Our Hero: A simple solution is to always set the reference qualifier from a script include.
Here's an example. We have a reference variable named v_configuration_item that is a reference to the cmdb_ci table in a single-row variable set that has been included in a number of catalog items. The simple reference qualifier for this variable, as seen when switching it to advanced, is:
sys_class_name=cmdb_ci_ip_router^ORsys_class_name=cmdb_ci_ip_switch
Example 1.1: This qualifier will only show routers and switches in the list of CI records.
In developing a new catalog item, we want to use this variable set, but for this CI variable we also want to show VPN (cmdb_ci_vpn) records. To meet this requirement, complete these steps:
1. Change the advanced Reference qualifier on the variable to something like:
javascript: new refQualUtils().getRefQual(current.cat_item,'sr.ref.vs.ci.cat_items','sr.ref_qual.ci.orig','sr.ref_qual.ci.new');
Example 1.2: Use any compliant names for a script include, function, and 3 system property names.
This reference qualifier will pass the catalog item sys_id and 3 system property names to a script include. Creating 3 system properties will allow us to re-use the script include function for other similar use cases, if the original and new reference qualifiers are simple enough to be stated in an encoded query string as in this example. For more advanced reference qualifiers, create only the first, or no, system properties, then use similar logic in the script include to ultimately return one of two complete reference qualifiers based on the catalog item sys_id.
2. Create a system property with the Value = the sys_id(s) of the catalog item(s) that will use the new reference qualifier. Separate sys_ids with a comma, a space, or your favorite emoticon {;-{)
3. Create a system property with the Value = the original reference qualifier.
4. Create a system property with the Value = the new reference qualifier.
5. Create a script include which will return the complete reference qualifier from one of the system properties, determined by the catalog item being included, or not, in the exception list system property:
varrefQualUtils = Class.create();
refQualUtils.prototype = {
initialize: function() {
},getRefQual: function(catItemID, propNameCatItem, propNameRQOrig, propNameRQNew) {
var answer = '';
if (gs.getProperty(propNameCatItem).indexOf(catItemID) != -1) { //catalog item found in the system property
answer = gs.getProperty(propNameRQNew); //use the new reference qualifier
} else {
answer = gs.getProperty(propNameRQOrig); //use the original reference qualifier
}
return answer;
},
type: 'refQualUtils'
};See AlsoBitburner Starter Pack
Now you can re-use a variable set, but change a reference qualifier for one or more catalog items, without adversely affecting the other catalog items using the variable set!
Scene 2: "You Complete Me"
An impressionable reference variable in the mysterious, beautiful world of the Multi-Row Variable Set has stars in its eyes over something beyond its grasp - an "Influencer" in the catalog item world. This Influencer is a variable with a valuable value that the reference variable in the MRVS world needs to make it work. Two worlds collide as the MRVS variable wants to "like and subscribe" to the catalog item variable's influential prowess. How can we bridge this great divide? "It can't be done." everyone says... Or can it? Will a heroic solution save the day once again, allowing the Influencer to build a following in the MRVS world?
Starting Point: A common workaround in this scenario is to create another variable in the MRVS. Then, in an onLoad script of the MRVS, populate this other variable on every row with the value of the catalog item variable to use in the reference qualifier (...current.variables.var_name).
Conflict: The downside to this workaround is creating and populating an unnecessary variable that can only be hidden in the Add/Edit Row dialog window, as all MRVS variables are always shown when a MRVS is displayed.
Our Hero: A simple solution is to use session data to complete the reference qualifier.
Here's an example. We have a catalog item reference variable named v_manager that is a reference to the sys_user table. In the MRVS we have a reference variable named v_employee that is a reference to the sys_user table. When adding or editing rows on the MRVS, before submitting the request and after, we should always only be able to select user records that are active, and the Manager is the user selected in the catalog item variable.
If the Employee variable was just another variable in the catalog item, the reference qualifier would easily be:
javascript: 'active=true^manager=' + current.variables.v_manager;
In a MRVS, since 'current' refers to the MRVS, and there is not (yet?) a similar method for reference qualifiers to access catalog item variables, we need to create a way. To meet this requirement, complete these simple steps:
1. Set the advanced reference qualifier on the MRVS variable to something like:
javascript:'active=true^manager=' + session.getClientData('v_manager');
Example 2.1: Use your catalog item variable name.
2. Create a catalog client script that applies to the Variable Set:
function onLoad() {
var catItemVarName = 'v_manager'; //catalog item variable name
var catItemVarValue = g_service_catalog.parent.getValue(catItemVarName);
var ga = new GlideAjax('refQualUtils'); //client callable script include name
ga.addParam('sysparm_name', 'setSessionData'); //function in script include
ga.addParam('sysparm_cat_item_var_name', catItemVarName);
ga.addParam('sysparm_cat_item_var_value', catItemVarValue);
ga.getXMLAnswer(getResponse);
}function getResponse(response) {
//do nothing
}
Example 2.2: Update the script as needed with your catalog item variable name, script include name, and a new function name.
3. Create aClient callablescript include to retrieve and set session data from the client script.
var refQualUtils = Class.create();
refQualUtils.prototype = Object.extendsObject(AbstractAjaxProcessor, {setSessionData: function() {
var catItemVarName = this.getParameter('sysparm_cat_item_var_name');
var catItemVarValue = this.getParameter('sysparm_cat_item_var_value');
var session = gs.getSession().putClientData(catItemVarName, catItemVarValue);
return;
},
type: 'refQualUtils'
});
Example 2.3: Since the catalog client script and script include use parameters, they can be re-used in every instance of this solution.
When the Add or Edit Rows MRVS window opens, the value of the catalog item variable is stored in the session data with the variable name, then the reference qualifier can retrieve the session data. See the ServiceNow Docs on GlideSessionfor more information about this API.
Now you can include values from catalog item variables in MRVS variable reference qualifiers!
FINAL NOTES:
- These solutions work in both the Native UI and Service Portal, and for catalog items that are standalone or are included in Order Guides!
Reference type variables are used in both examples, but the same should work for List, List Collector, Lookup Select Box... any field or variable type that has a reference qualifier!
- Everything I am using in these examples is in the global scope. If you have catalog items, scripts, or fields in different applications, adjust the calls accordingly.
- If you haven't seen this before, this editor has a bad habit of messing up javascript followed by the colon character, so everywhere you see 'javascript:', replace that with
- Please comment with your ideas on how to enhance this solution, in the spirit of continuous learning and improvement for all.