

- Post History
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
on ‎06-24-2022 10:46 AM
Have you ever had a need to be able to access Order Guide variables within the Order Guide script field?
Within Order Guides there really isn't an efficient way to access the Order Guide variables within the Order Guide script field as easy as you can within a Record Producer. Within a Record Producer, you can access the variables by simply using: producer.variable_name.
For Order Guides, sure you can cascade the values and/or use a "Rule base" to look at the variables and their values and then add catalog items dynamically that way or set specific field values on that catalog item based on an order guide variable's value, but we're talking about the Order Guide script field.
The Order Guide script field is executed once you click the "Next" or "Choose Options" button on the initial order guide page and proceed to the next steps.
Possible Use Cases: Common use cases for this script field is to dynamically add catalog items to the order guide process in an automated way when you're in a situation where you may not want to setup your Rule base to house tons of catalog items (i.e., you need to check a value on another table, then based on that and various Order Guide variable values, you may need to add 5 random catalog items for this user). Another use case could be that you need to execute some sort of server side script to capture something somewhere else and need access to the Order Guide variables and their values to complete this task.
In any case, previously, this question has mostly gone unanswered or partially answered. For example, there's been the suggestion to use something like this in the order guide script field to get the value of a particular Order Guide variable:
g_request.getParameter('IO:sys_id_of_variable')
But that doesn't work on the Portal...
Then there's actually a way to access the Order Guide variables and their values within the sc_cart record for the user as the data is captured within the "Current guide serial" field, but it contains the variable sys_ids without their variable names and requires you to either use that variable sys_id or do a lookup within the database and retrieve the variable name (or label) and even then it's still a bit of a mess that you have to filter through as it's just one massive block of string, example:
Who knows, maybe you didn't even know about that field and want to stop reading here and can use that and you'll take it from here. If so, by all means, go for it!
Use Case for this Article: Let's say we have a New Hire order guide and based on the value of the order guide reference variable "hiring_group", this determines if we need to add a specific catalog item to this process. That catalog item is saved in a separate reference field within the selected group's sys_user_group record.
Solution: The solution I'm proposing helps organize things a bit more and makes it easier to use the data to then do whatever you need to do. It requires an onChange Client Script for each of the variables where you'd like to capture both the variable name and the value and uses GlideAjax to communicate with a script include. A client callable script include to be leveraged by the GlideAjax call which executes server script to record the data to the user's relevant service catalog cart record. And then of course the script you need in your Order Guide script field.
Solutions Steps:
- Create a client callable script include named: orderGuideVars and check the "Client callable" checkbox prior to writing any script:
And the full script can look like this (you can copy and paste the entire thing and replace what you have):
var orderGuideVars = Class.create(); orderGuideVars.prototype = Object.extendsObject(AbstractAjaxProcessor, { addVariable: function() { var guideID = this.getParameter('sysparm_guideID'); //retrieves the order guide sys_id from the client script var varName = this.getParameter('sysparm_varName'); //retrieves the order guide variable field name from the client script var varValue = this.getParameter('sysparm_varValue'); //retrieves the order guide variable value from the client script var userID = this.getParameter('sysparm_userID'); //retrieves the current user's sys_id from the client script var obj; //declares a JavaScript variable called obj for use later in the script //declares a JavaScript variable called runUpdate that will run function updateCart passing in parameters that we retrieve earlier in this script //the function will return true if a cart record associated with the order guide is found for this user //the function will return false if no cart record associated with the order guide is found for this user var runUpdate = updateCart(guideID, varName, varValue, userID); if (!runUpdate) { //if runUpdate equals false //execute function updateDefault to instead update the default cart record for this user passing in just the variable name, variable value, and the user's sys_id we retrieved earlier in this script updateDefault(varName, varValue, userID); } function updateDefault(varName, varValue, userID) { var gr = new GlideRecord('sc_cart'); //preparing to query the sc_cart table gr.addQuery('name', "DEFAULT"); //filter for records where the name is DEFAULT gr.addQuery('user', userID); //filter for record's associated to user's sys_id gr.query(); //execute the query if (gr.next()) { //if a record is found that matches the above, proceed try { //try the below first obj = JSON.parse(gr.special_instructions); //set JavaScript variable 'obj' to the parsed value of the special instructions field obj[varName] = varValue; //set the key value pair related to the order guide variable name and value, within the object } catch (e) { //if an error occurs from the above, proceed with catch obj = {}; //set JavaScript variable 'obj' as an object obj[varName] = varValue; //set a key value pair related to the order guide variable name and value, within the object } gr.setValue('special_instructions', JSON.stringify(obj)); //set the special instructions field to the stringified JavaScript variable 'obj' gr.update(); //update the cart record } return true; //return true } function updateCart(guideID, varName, varValue, userID) { var gr = new GlideRecord('sc_cart'); //preparing to query the sc_cart table gr.addQuery('current_guide', guideID); //filter for records that have the current guide field related to the order guide gr.addQuery('user', userID); //filter for record's associated to user's sys_id gr.query(); //execute the query if (gr.next()) { //if a record is found that matches the above, proceed try { //try the below first obj = JSON.parse(gr.special_instructions); //set JavaScript variable 'obj' to the parsed value of the special instructions field obj[varName] = varValue; //set the key value pair related to the order guide variable name and value, within the object } catch (e) { //if an error occurs from the above, proceed with catch obj = {}; //set JavaScript variable 'obj' as an object obj[varName] = varValue; //set a key value pair related to the order guide variable name and value, within the object } gr.setValue('special_instructions', JSON.stringify(obj)); //set the special instructions field to the stringified JavaScript variable 'obj' gr.update(); //update the cart record return true; //return true } else { return false; //return false } } return ''; //return null to client script -- nothing is really needed to go back to the client script anyway }, type: 'orderGuideVars' });
- Create an onChange Client Script for however many order guide variables you want to capture the name and value of. It's recommended to use settings like this:
And the full script can look like this (you can copy and paste the entire thing and replace what you have):
function onChange(control, oldValue, newValue, isLoading) { if (isLoading || newValue == '') { return; } var guideID; //creating JavaScript variable called guideID if (g_form.getUniqueValue()) { //if g_form.getUniqueValue() returns a valid value, then proceed guideID = g_form.getUniqueValue(); //sets the JavaScript variable 'guideID' to the sys_id of the order guide - Portal UI } else { //if g_form.getUniqueValue() returns an invalid value, then proceed guideID = g_form.getParameter('sysparm_guide'); //sets the JavaScript variable 'guideID' to the sys_id of the order guide - Platform UI } var ga = new GlideAjax('orderGuideVars'); //preparing a call to the script include 'orderGuideVars' ga.addParam('sysparm_name', 'addVariable'); //calling the specific function in the orderGuideVars script include called addVariable ga.addParam('sysparm_guideID', guideID); //passing the order guide sys_id to the script include ga.addParam('sysparm_varName', 'replace_with_order_guide_variable_name'); //passing the order guide variable name to the script include ga.addParam('sysparm_varValue', newValue); //passing the new value selected for this order guide variable to the script include ga.addParam('sysparm_userID', g_user.userID); //passing the current user's sys_id to the script include ga.getXMLAnswer(callBackFunc); //executing the GlideAjax call } function callBackFunc(response) { //receiving response from the script include -- no real response is needed // }
- Lastly, you can now parse the special instructions field on the current record to then add a catalog item as you need. You can access any order guide variable that you used the onChange Client Script with by referring to it as: obj.variable_name. In this case, we will query the sys_user_group table and use the hiring_group order guide variable (that we're using in this example use case) to retrieve the custom field's value we placed on the group table that houses the special catalog item we want to add to this order guide process. The script would look something like this:
var getCart = new GlideRecord('sc_cart'); //preparing to query the sc_cart table getCart.get(current.sys_id); //retrieving the current order guide record for this user var obj = JSON.parse(getCart.special_instructions); //setting the JavaScript variable 'obj' to the parsed value of the special instructions field on the retrieved sc_cart record found above var getItem = new GlideRecord('sys_user_group'); //preparing to query the sys_user_group table getItem.get(obj.hiring_group.toString()); //retrieving the hiring group's group record that was selected on the order guide form guide.add(getItem.getValue('u_custom_catalog_item')); //adding the special catalog item to this order guide process that is listed on the hiring group's group record
- Additional note, you can also use guide.remove('sys_id_of_catalog_item'); as well, if needed
Documentation: Order Guide Script field: https://docs.servicenow.com/en-US/bundle/sandiego-servicenow-platform/page/product/service-catalog-m...
----------
Shoutout/Additional Credit: I want to give a special shoutout to
Since then, I've seen this question pop-up a few times and I hadn't really had the time to take things a bit further and write an article, but...better late than never, so here it is. I've taken what was discussed in that thread and then tweaked things a bit to ensure it works in a wider setting, for the right user, for the right service catalog cart record.
----------
If you have any questions/concerns/issues, feel free to comment below
*Please don't forget to mark this article as Helpful and Bookmark it!
Thank you and take care!
- 11,765 Views
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Thx for mentioned it (me). 🙂
Was there a rule, never ever use gr 🙂


- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
It's wrapped in a function 😉
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Thx, this works beautifully as far as selecting and adding the additional cat items to the order... However! After the summary, once I submit, the extra items (highlighted) don't create RITMs...
only the Email Account, which was rule-based. I have tried it without a rule-based item too, and nothing gets created.
Thoughts? Something missing in my cart configuration perhaps?
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
It seems to be something to do with my instance creating a default cart and sometimes an order-guide-specific cart, seems to be getting tangled up....
eg. Carla Humble, new user, no carts... when she opens a cat item form, a default cart gets created. When she changes my variables (persona and job title) your script updates the only cart for Carla, the default one. But when she clicks choose options, a new cart is created specific to this order guide sys id.. but the variables are not on this guide so the order guide script returns empty values from the special instructions obj.
Is this correct default behaviour for carts or is there a cart setting I am missing?
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
I fixed my cart problem by altering your suggested order guide script to:
var getCart = new sn_sc.CartJS();
var obj = JSON.parse(getCart.getSpecialInstructions());

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Thank you so much . This is great !

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Allen
Thank you very much for providing this great functionality!
I noticed that sometimes there are some issues in the following cases:
- User goes on second page and goes back on first page
- User has no Default Cart
- Order Guide Script takes only Special Instruction value from specific cart
To fix this issues I have modified the following scripts (refer to the large comment lines):
Script Include:
- Create default cart if user has no default cart
addVariable: function() {
var guideID = this.getParameter('sysparm_guideID'); //retrieves the order guide sys_id from the client script
var varName = this.getParameter('sysparm_varName'); //retrieves the order guide variable field name from the client script
var varValue = this.getParameter('sysparm_varValue'); //retrieves the order guide variable value from the client script
var userID = this.getParameter('sysparm_userID'); //retrieves the current user's sys_id from the client script
var obj; //declares a JavaScript variable called obj for use later in the script
//declares a JavaScript variable called runUpdate that will run function updateCart passing in parameters that we retrieve earlier in this script
//the function will return true if a cart record associated with the order guide is found for this user
//the function will return false if no cart record associated with the order guide is found for this user
var runUpdate = updateCart(guideID, varName, varValue, userID);
if (!runUpdate) { //if runUpdate equals false
/////////////////////////////////////////////////////////////////////////////////////////////
//This is the code I have added to fix the issue with no default cart
//Generate default cart if cart does not exist
var cart = new sn_sc.CartJS();
/////////////////////////////////////////////////////////////////////////////////////////////
//execute function updateDefault to instead update the default cart record for this user passing in just the variable name, variable value, and the user's sys_id we retrieved earlier in this script
updateDefault(varName, varValue, userID);
}
function updateDefault(varName, varValue, userID) {
var gr = new GlideRecord('sc_cart'); //preparing to query the sc_cart table
gr.addQuery('name', "DEFAULT"); //filter for records where the name is DEFAULT
gr.addQuery('user', userID); //filter for record's associated to user's sys_id
gr.query(); //execute the query
if (gr.next()) { //if a record is found that matches the above, proceed
try { //try the below first
obj = JSON.parse(gr.special_instructions); //set JavaScript variable 'obj' to the parsed value of the special instructions field
obj[varName] = varValue; //set the key value pair related to the order guide variable name and value, within the object
} catch (e) { //if an error occurs from the above, proceed with catch
obj = {}; //set JavaScript variable 'obj' as an object
obj[varName] = varValue; //set a key value pair related to the order guide variable name and value, within the object
}
gr.setValue('special_instructions', JSON.stringify(obj)); //set the special instructions field to the stringified JavaScript variable 'obj'
gr.update(); //update the cart record
}
return true; //return true
}
function updateCart(guideID, varName, varValue, userID) {
var gr = new GlideRecord('sc_cart'); //preparing to query the sc_cart table
gr.addQuery('current_guide', guideID); //filter for records that have the current guide field related to the order guide
gr.addQuery('user', userID); //filter for record's associated to user's sys_id
gr.query(); //execute the query
if (gr.next()) { //if a record is found that matches the above, proceed
try { //try the below first
obj = JSON.parse(gr.special_instructions); //set JavaScript variable 'obj' to the parsed value of the special instructions field
obj[varName] = varValue; //set the key value pair related to the order guide variable name and value, within the object
} catch (e) { //if an error occurs from the above, proceed with catch
obj = {}; //set JavaScript variable 'obj' as an object
obj[varName] = varValue; //set a key value pair related to the order guide variable name and value, within the object
}
gr.setValue('special_instructions', JSON.stringify(obj)); //set the special instructions field to the stringified JavaScript variable 'obj'
gr.update(); //update the cart record
return true; //return true
} else {
return false; //return false
}
}
return ''; //return null to client script -- nothing is really needed to go back to the client script anyway
},
Order Guide Script:
- Check if Special Instructions from specific cart are available
- If not, take Special Instructions from default cart
- At the end, clear the Special Instructions from default cart
- If not, take Special Instructions from default cart
var catalogItemSysIds;
var getCartFromOrderGuide = new GlideRecord('sc_cart'); //preparing to query the sc_cart table
getCartFromOrderGuide.get(current.sys_id); //retrieving the current order guide record for this user
if(getCartFromOrderGuide.special_instructions){
var obj = JSON.parse(getCartFromOrderGuide.**VARIABLE_NAME**); //setting the JavaScript variable 'obj' to the parsed value of the special instructions field on the retrieved sc_cart record found above
if(obj.**VARIABLE_NAME**){
catalogItemSysIds = obj.**VARIABLE_NAME**.split(',');
}
}
if(!catalogItemSysIds){
//Get Default cart from user
var getCartDefault = new sn_sc.CartJS();
var objDefault = JSON.parse(getCartDefault.getSpecialInstructions());
catalogItemSysIds = objDefault.**VARIABLE_NAME**.split(',');
}
if(catalogItemSysIds.length > 0){
for(var index in catalogItemSysIds){
var grPSCI = new GlideRecord('pc_software_cat_item');
if(grPSCI.get(catalogItemSysIds[index])){
guide.add(grPSCI.getUniqueValue());
}
}
}
//Check if Default Cart has special instructions with "**VARIABLE_NAME**"
var cart = new sn_sc.CartJS();
if(cart.getSpecialInstructions().indexOf('**VARIABLE_NAME**') > -1){
//Clear special instructions
cart.setSpecialInstructions('');
}
Regards,
Roy
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi @Allen Andreas
Is this article work for following scenario.
i have a task when an order guide is requested,In that one of the item (X) is removed manually and then when request is created.The X item should be added automatically with necessary variables.Is that possible?


- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi prem,
My article is about accessing the order guide variables to then do something else.
For your scenario, it sounds like it may be better for you to make the catalog item mandatory so that they don't remove it. Here's another article which explains one way on how to do that: https://www.servicenow.com/community/it-service-management-articles/mandatory-rule-base-in-order-gui...
Thanks!

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Wow! Great article, thank you for this!
Years later, I find that we are still struggling with this - with our software items. We use Client Software Distribution (CSD) and we have a lot of software packages available. It works but portal wise, it's a mess. The guys creating the software packages also have access to create the software items in ServiceNow, but not a lot of other access and I don't think that want it differently.
We don't have a good category structure as the data quality is poor. So you can just go in and either browser through available software items or search if you know exactly what you want. Not a good user experience.
When I asked this question back in 19 I were not ready for client side/server side scripting with ajax calls to script includes etc .. it was way too advanced for me, but luckily I'm still working with this great platform and I learn every day. I could certainly manage to do so now.
However, I also cannot help thinking is this really the best way? Much time has passed.. do we have other and better options today?
In general I want to build stuff working dynamically so that our packaging team would need to do as little as possible (but of cause we need better data quality, for example some categories) for making it available on the portal and also I don't want a task in the future development of software packages, whenever there are new packages available, as I would become a huge bottleneck. Our ServiceNow team is inhouse only and tiny.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Can order guide variables be accessed via the Reporting Module? I have a requirement to report on an order guide variable that isn't passed to a catalog item. I don't see a way to do this but your article here is quite extensive so hoping you have some insight!

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
You could just create a hidden variable on the catalog item and then pass it. Then it is available for reporting.