
- Post History
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
on 02-08-2020 12:15 PM
Multi-Row variable sets were introduced in London and were something of a game changer; they finally provided an in-platform method for capturing repeatable datasets dynamically. Before they were an option you had to go to somewhat extreme measures to achieve the same functionality with a custom solution, which came with its own set of challenges and drawbacks. Suffice to say they are a fantastic addition to the platform but, there are some situations where they don't function the way you would hope (or expect).
A good example of this would be the fact that when you write a catalog client script within the Multi-Row Variable set, by default the script can only access and influence variables that are included in the MRVS. If you try to use a standard method and call a variable that is outside of the MRVS, you get no results. Things like g_form.getValue() and g_form.setValue() return no results (and no hard errors). Most of the time this isn't really an issue, but in certain circumstances you might find it beneficial to either pull in existing values from your catalog item, or to set values on the catalog item, in response to selections your user is making on the MRVS.
If your catalog item is being used via the Service Portal, unfortunately you are still out of luck, at least without some heavy customizations that are strongly discouraged. If however your item is being used via the UI then you can accomplish this with a relatively easy configuration! One caveat is that this is not a best-practice as it requires the use of the window object so, use with careful consideration.
Native UI:
For example, say you want to use a value selected in a select box named "hardware_type" to set the value of a select box called "type" on your MRVS when a new row is added, you could do the following.
Create the variable on the Catalog Item and populate it with whatever options you want to include.
Create the variable on the MRVS with no options.
Create an On Load Catalog Client Script on your MRVS.
Enter a script like this:
function onLoad() {
var option = parent.g_form.getValue('hardware_type');
g_form.addOption('type', option, option);
}
For the next step, you have two options.
You can configure the catalog client script form to include the Isolate Script field. Once it is visible, uncheck it.
Alternately you can view the script in the list view, add the field to the list and set it to false from there.
The result will be something like this:
The reason this works? The MRVS is called within an iframe, which is isolated from the main window and prevents scripts called locally from interacting with elements outside of the iframe. By allowing the use of Globals and calling window.parent before the function you pass the call to the parent and the response is passed back to the child.
While the example I provide is somewhat simple, the basic principle can be used to accomplish some interesting results. In fact the process can be used in both directions; by calling window.parent.setValue() you can update values on the Catalog Items, based on selections in the MRVS, in real time. For example you could keep a running total cost of all items added via the MRVS for validation.
While this isn't something I would suggest using excessively, there are some situations where there simply isn't another way to achieve the same results so, it's a useful trick to have available.
Update for Service Portal:
For those looking for a solution that works in the Service Portal as well as the native UI, there are a couple of methods floating around. One is mentioned in the comments here by Rupam; they mention that something like this might be a workaround for the portal as an onload script in the variable set:
var catItem = spThis.angular.element(spThis.$('#sc_cat_item').find('sp-variable-layout')[0]).scope();
var parent_g_form = catItem.getGlideForm();
parent_g_form.setValue('field', 'value');
I've seen this approach work, and also not work, and I wasn't able to explain why in either case so, I've kept searching.
While trying to do something unrelated I stumbled across a method that seems to work reliably, at least thus far.
You would need to create an Onload script in your catalog item, with isolate script set to false:
function onLoad() {
//We need to make the g_form object for the parent item available for later
this.cat_g_form = g_form;
}
Once that is in place, you can use something like in a script on the MVRS (also set to isolate script false). This example sets a field on the parent catalog item when a particular checkbox is selected on an MVRS row, and (in combination with the above script) works for both Portal and Native UI.
function onChange(control, oldValue, newValue, isLoading) {
if (isLoading || newValue == '') {
return;
}
//Service Portal logic
if (this) {
this.cat_g_form.setValue('some_textfield', 'Some option included in MRVS');
} else {
//Native UI logic
parent.g_form.setValue('some_textfield', 'Some option included in MRVS');
}
}
This has been working reliably in all of the situations where I've used it, so I wanted to share this method as well.
If you found this article helpful or useful, please be kind and click appropriately. If you found it really useful, you could always use the 3-dot menu to bookmark it for later!
Michael Jones - Proud member of the CloudPires team!
- 38,024 Views
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi,
I have one issue about this.
i have company variable outside MRVS.
in MRVS i have user field. i want to use company value in user field reference qualifier.
How to get that value.Please help me.
Thank you.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Michael,
I was chasing this question for quite a long time, until today.
I am currently working on Connected Workplace (ServiceNow store application) for one of my clients. In this application, I was looking at one of the catalog that was pre-build and it did contain MRVS.
To my surprise, I found that they were populating the fields in MRVS based on the variables of the catalog and they were doing this both on the portal and the Native UI. I went ahead and checked the onLoad client script in the MRVS and I found below.
function onLoad() {
var siResponse = [];
var spThis = this;
// Service Portal Section
if(spThis){
var catItem = spThis.angular.element(spThis.$('#sc_cat_item').find('sp-variable-layout')[0]).scope();
var parent_g_form = catItem.getGlideForm();
var parentRequestDateSP = parent_g_form.getValue('requested_move_date');
var parentSiteSP = parent_g_form.getValue('site');
var parentFloorSP = parent_g_form.getValue('floor');
var parentCostCenterSP = parent_g_form.getValue('cost_center');
var parentCvxLocationSP = parent_g_form.getValue('location');
g_form.setValue('employee_requested_move_date', parentRequestDateSP);
g_form.setValue('to_home_base', parentSiteSP);
g_form.setValue('to_floor', parentFloorSP);
g_form.setValue('user_cost_center', parentCostCenterSP);
if (parentCvxLocationSP == 'non_c') {
var ga = new GlideAjax('DateUtils');
ga.addParam('sysparm_name','getNonCLocation');
ga.getXML(getData);
}
}
//Native UI Section
else {
var parentRequestDate = window.parent.g_form.getValue('requested_move_date');
var parentSite = window.parent.g_form.getValue('site');
var parentFloor = window.parent.g_form.getValue('floor');
var parentCostCenter = window.parent.g_form.getValue('cost_center');
var parentCvxLocation = window.parent.g_form.getValue('location');
g_form.setValue('employee_requested_move_date', parentRequestDate);
g_form.setValue('to_home_base', parentSite);
g_form.setValue('to_floor', parentFloor);
g_form.setValue('user_cost_center',parentCostCenter);
if (parentCvxLocation == 'non_c') {
var ga2 = new GlideAjax('DateUtils');
ga2.addParam('sysparm_name','getNonCLocation');
ga2.getXML(getData);
}
}
function getData(response){
var answer = response.responseXML.documentElement.getAttribute("answer");
siResponse = answer.toString().split('||');
g_form.setValue('to_home_base',siResponse[2]);
g_form.setValue('to_floor',siResponse[1]);
g_form.setValue('to_space',siResponse[0]);
g_form.setReadOnly('to_home_base','true');
g_form.setReadOnly('to_floor','true');
g_form.setReadOnly('to_space','true');
g_form.setVisible('to_home_base','false');
g_form.setVisible('to_floor','false');
g_form.setVisible('to_space','false');
g_form.setMandatory('notes', true);
g_form.showFieldMsg('notes','Include the Non-C Address','error',true);
}
}
After this I tried analyzing the below 2 lines. I googled it, but no luck. So I tried googling it with "how to pass data to multi row variable set client script from catalog variables" and I came across your article, but for you as well it wasn't working on the portal.
var catItem = spThis.angular.element(spThis.$('#sc_cat_item').find('sp-variable-layout')[0]).scope();
var parent_g_form = catItem.getGlideForm();
Hopefully this helps someone. I am still looking for information on this getGlideForm() and the angular dot-walking on the DOM to the MRVS.

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Excellent, thank you for sharing this information. I'm sure others will find it useful as well!
I'll definitely spend some time looking into this as this has been a (minor) thorn in my side far too often 🙂
Thanks again!
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
It worked !!

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Updated to include a reliable way to access Catalog Item elements from a Multi-Row Variable Set in the Service Portal as well as the Native UI.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi,
This works! The only issue is that the service portal part does NOT work in ATF.
The following part does not return a value
spThis.$('#sc_cat_item').find('sp-variable-layout')[0]
I also tried replacing the $ with jQuery but still no luck.
Have you experienced this in ATF?
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Starting Quebec, you can now use the g_service_catalog API which is available in all environments, such as, Service Portal, Now Platform, Workspace, and Now® Mobile.
It's also not working on ATF, and I will have to report this to ServiceNow to fix.
https://developer.servicenow.com/dev.do#!/reference/api/rome/client/g_service_catalogClientAPI#g_service_catalog-getValue_S?navFilter=g_service_catalog
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Michelhanna,
Yes, starting with Quebec we have this g_service_catalog API but it is available only for getting the value using the "getValue(String variableName)" and doesn't have setValue function.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
hello, I have cost field in the row of MRVS and for every row we will add different cost..
Lets say cost -- 100 in one row and cost 200 in other row.. I want to add the cost and the total should populate in a new variable below. Is it possible?
You can see cost 100 and 300. When ever a row is added and they add cost it should add all the costs and update in Total cost. Do you have any idea on this?
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi
Apologies for the delayed response
Use as below
var mrvsRows = g_form.getValue("mrvs_name");
//The above will return a string in the form of array and objects. Now you will have to parse it
var oMrvs = JSON.parse(mrvsRows);
var sum = 0;
for(var i in oMrvs) {
sum += oMrvs[i]["cost_field_name"]
}
g_form.setValue("total_cost_field_name", sum);
Thanks
Rupam
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
This worked for me, Thanks for sharing.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hye did you get the solution for this?
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi
How would I use this to update quantity based on mrvs rows, in Service Portal/Employee Centre?
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
I have also used below line of code in onSubmit() catalog client script of a multi row variable set to set the variable outside the MRVS.
function onSubmit(){
var catItem = spThis.angular.element(spThis.$('#sc_cat_item').find('sp-variable-layout')[0]).scope();
var parent_g_form = catItem.getGlideForm();
parent_g_form.setValue('field', 'value');
}
Its working on portal side and populated the field value in the case form when I am submitted the Record producer but whenever the case is opened in the native UI and edited the Multi Row Variable set, while submitting a MRVS in case form, some times it is showing script error like this "onSubmit script error: TypeError: Cannot read properties of undefined (reading 'element'):". I am enclosed error screenshot.
Please help me to fix this issue.
Thanks in advance.
With Regards
P. Siva.

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Great, thank you so much for sharing!