Multi-Row Variable Sets: How to get or set values for variables outside of the MRVS (Native UI or Service Portal)
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!
https://www.servicenow.com/community/developer-articles/multi-row-variable-sets-how-to-get-or-set-values-for-variables/ta-p/2324715