Interested in a ServiceNow event built for developers? Registration for now[dev]26 is officially open!

Brad Tilton
ServiceNow Employee

In my last post, we created a multi-row variable set, added variables, then showed it in action by filling out the variables and checking out. In this post we'll use some of the new methods described here to access and set values. For the purposes of this post we're going to be using background scripts (which received some new functionality in London) in the global scope. 

The first thing we'll look at is the JSON object returned by referencing the MRVS. In the following script we're using the sys_id of therequest item ordered in the last post to get the GlideRecord object for that request item. Then we're populating the mrvs variable with the access_list variable set.

 

var mrvs;
var itemID = '70506da8db002300e69dfbef2996194a';
var ritmGR = new GlideRecord('sc_req_item');
if (ritmGR.get(itemID)) {
    mrvs = ritmGR.variables.access_list;
}
gs.print(mrvs);

 

Returns:

 

*** Script: [ {
  "application" : "829e953a0ad3370200af63483498b1ea",
  "access_level" : "read"
}, {
  "application" : "2811a2efc0a8000b0069bb464f215ff5",
  "access_level" : "full",
  "business_justification" : "This field is mandatory because I selected full access"
}, {
  "application" : "28110ea1c0a8000b003abee48ecbc3fa",
  "access_level" : "read_write"
} ]

 

The first thing I noticed was that it appears that only variables with values are included in the json object as the first and third elements don't have a business_justification. From here, we can get more granular.

NOTE: In order to save space the following scripts will assume we have the variable mrvs from the first script above that represents the multi-row variable set. 

 

//get all the values in a single column
gs.print(mrvs.application);
//get the number of rows in the multi-row variable set
gs.print(mrvs.getRowCount());

 

Returns:

 

*** Script: [829e953a0ad3370200af63483498b1ea, 2811a2efc0a8000b0069bb464f215ff5, 28110ea1c0a8000b003abee48ecbc3fa]
*** Script: 3

 

Based on this we see that we can use the variableset.variablename will give us all of the values from the variables column in an array. This could be useful if we wanted to do some sort of check against the applications before looking at the level of access needed. We also see that we have the familiar getRowCount() to use to see how many rows are in the MRVS. We can also usevariableset = <JSON Object> and variableset.variablename = <Array of values> to set values or the whole variable set or all rows in a column.

Now we'll use getRowCount and getRow to iterate through the rows, and then getRow to print the values of our application and access_level variables:

 

var rowCount = mrvs.getRowCount();
for (var i = 0; i < rowCount; i++) {
	var row = mrvs.getRow(i);
	var app = row.application;
	var accessLevel = row.access_level;
	gs.print(app + ' ' + accessLevel);
}

 

Returns:

 

*** Script: 829e953a0ad3370200af63483498b1ea read
*** Script: 2811a2efc0a8000b0069bb464f215ff5 full
*** Script: 28110ea1c0a8000b003abee48ecbc3fa read_write

 

Now we're going to use addRow to add a row and populate the variables in the row using setCellValue and setting it directly using the row objects property for the variable:

 

var newRow = mrvs.addRow();
//set the value using row.setCellValue('<var_name>',value)
newRow.setCellValue('application', '829e953a0ad3370200af63483498b1ea');
//set the value using row.<var_name> = value
newRow.access_level = 'read_write';
gs.print(mrvs);

 

Returns:

 

*** Script: [ {
  "application" : "829e953a0ad3370200af63483498b1ea",
  "access_level" : "read"
}, {
  "application" : "2811a2efc0a8000b0069bb464f215ff5",
  "access_level" : "full",
  "business_justification" : "This field is mandatory because I selected full access"
}, {
  "application" : "28110ea1c0a8000b003abee48ecbc3fa",
  "access_level" : "read_write"
}, {
  "application" : "829e953a0ad3370200af63483498b1ea",
  "access_level" : "read_write"
} ]

 

We now have a fourth row in the catalog table variable with the values we set in the script. Notice that both methods worked to set the values. There's also a method for deleting a row, but I'm usually against deleting anything in ServiceNow so I'm not going to use it here. 

Lastly, I wanted to post the notes and limitations from the docs article here as they're important to know when working with the MRVS:

  1. You can only set a variable in a before business rule. Variables set in an after rule are not written to the database.
  2. There is nothing in place to prevent namespace collision with variables. Creating two variables named computer_speed would result in only one of them showing up; the second one would overwrite the first one.
  3. Date/time variables use the same time zone formatting and storage rules as all other dates in the system. They are stored internally in GMT, but translated into the user's local time zone and format for display.

I hope this post was helpful as you're exploring how to use the values from London's new Multi-row variable set in your workflows, scheduled jobs, and business rules.

 

151 Comments
Brad Tilton
ServiceNow Employee

Fixed it, thanks Jim!

Swathi P
Kilo Sage

Hi Brad.. This is very informative. How to get values on client side. 

Eash1
Tera Expert

Thank you Brad,

 

Any inputs on below questions reg Multi-row 

 

  • How to make sure at-least one entry is selected as part of Multi row variable set. I tried to do an on-submit and later read through docs that it is not supported
  • How to limit number of entries ? like just 10

Thank you,

Easwar

Brad Tilton
ServiceNow Employee

You can run onload and onsubmit client scripts on the variable set itself, and they run when you add or submit each individual row. I would start there, but I'm not quite sure how much validation you'll be able to do that way.

Jeremy Estes
Mega Contributor

Figured out the issue: I was using the "$$" directive in my "Hide Buttons" client script for DOM manipulation. I disabled this by adding the "Isolate script" field to the catalog client script form and unchecking it.

I needed to hide the add and remove buttons on just the first mrvs in my form. Still trying to figure out how to hide the remove row button but keep the edit row button.

function onLoad() {
  var add = 0;
  var removeall = 0;
  var items = $$('BUTTON').each(function(item) {
    if (item.innerHTML == 'Add' && add < 1) {
      item.hide();
      add++;
    }
    if (item.innerHTML == 'Remove All' && removeall < 1) {
      item.hide();
      removeall++;
    }
  });
}

 

brianlan25
Kilo Patron

Is there a way to loop through the variables so I can set some fields on the incidents form.  Right now I have a bunch of check boxes for each day of the week and then a start time and end time to collect building access hours.  I have created a mrvs with a drop down for the Day of week.  I cannot change my incident fields as they are already part of an integration but I need some way to set the appropiate checkbox for the day of the week as well as the times for that day of the week.  Below is an example of my mrvs.

 

Here is how the fields look on my incident form.

Goran WitchDoc
ServiceNow Employee

Hi,

 

I made a video how to do this with a Catalog Client Script: https://youtu.be/JZ341t0iVtY

//Göran
Feel free to connect with me:
 
Ashutosh Munot1
Kilo Patron

Hi,

 

We created a Before BR and i am getting values in log but they are not getting inserted into table and not visible on Table on RITM.


Please see below code:

(function executeRule(current, previous /*null when async*/) {

var getAsset = new GlideRecord('alm_asset');
getAsset.addQuery('request_line',current.parent);
getAsset.query();
if(getAsset.next()){
gs.log('Receive Count '+getAsset.getRowCount(),'NETWORK RECEIVING');
var mrvs;
var itemID = current.sys_id;
var ritmGR = new GlideRecord('sc_req_item');
if (ritmGR.get(itemID)) {
mrvs = ritmGR.variables.receive;
gs.log('mrvs '+mrvs,'NETWORK RECEIVING');
}

var newRow = mrvs.addRow();
newRow.setCellValue('asset',getAsset.sys_id.toString());
newRow.setCellValue('serial_number','TEST098098');
gs.log('mrvs 2 '+mrvs,'NETWORK RECEIVING');

}

})(current, previous);

 

LOGS:

1) Receive Count 2

2) mrvs []

3)

mrvs 2 [ {
"asset" : "0bd991ff1bbeeb00109386ae6e4bcb71",
"serial_number" : "TEST098098"
} ]

 

 


Thanks,
Ashutosh

Brad Tilton
ServiceNow Employee

I'm not sure this would affect the variables getting inserted, but if the BR is running on the RITM you don't need to use .get to get the record. Try something like this:

(function executeRule(current, previous /*null when async*/ ) {

    var getAsset = new GlideRecord('alm_asset');
    getAsset.addQuery('request_line', current.parent);
    getAsset.query();
    if (getAsset.next()) {
        gs.log('Receive Count ' + getAsset.getRowCount(), 'NETWORK RECEIVING');
        var mrvs current.variables.receive;
        gs.log('mrvs ' + mrvs, 'NETWORK RECEIVING');

        var newRow = mrvs.addRow();
        newRow.setCellValue('asset', getAsset.getValue('sys_id'));
        newRow.setCellValue('serial_number', 'TEST098098');
        gs.log('mrvs 2 ' + mrvs, 'NETWORK RECEIVING');

    }

})(current, previous);

If that still doesn't work you might need to open a hi ticket.

Ashutosh Munot1
Kilo Patron

HI Brad,


Just did it via script include.

Thanks,
Ashutosh