H
ere’s a cool catalog client script that I figured out for a client. It allows you to move one or more selected options from one side of a list collector variable slushbucket to another. Using the script is pretty straight forward. Just supply the name of the list collector variable you are working with, and then make sure you provide an array of option IDs to move from one side to another. The option IDs need to be added to the ‘selectedIDs’ array in the middle chunk of code. The code below is set up to move ALL options in the right column of a slushbucket to the left.
//Name of variable to move options from
var varName = 'YOUR_VARIABLE_NAME_HERE';
var leftBucket = gel(varName + '_select_0');
var rightBucket = gel(varName + '_select_1');
var selectedOptions = rightBucket.options;
//Get an array of all option IDs to move
var selectedIDs = new Array();
var index = 0;
for(var i = 0; i < selectedOptions.length; i++){
selectedIDs[index] = i;
index++;
}
//Move all returned options from right to left bucket and sort the results
//Switch 'rightBucket' and 'leftBucket' to move from left to right
moveSelectedOptions(selectedIDs, rightBucket, leftBucket, '--None--');
//Sort the resultant options in the left bucket
sortSelect(leftBucket);
var varName = 'YOUR_VARIABLE_NAME_HERE';
var leftBucket = gel(varName + '_select_0');
var rightBucket = gel(varName + '_select_1');
var selectedOptions = rightBucket.options;
//Get an array of all option IDs to move
var selectedIDs = new Array();
var index = 0;
for(var i = 0; i < selectedOptions.length; i++){
selectedIDs[index] = i;
index++;
}
//Move all returned options from right to left bucket and sort the results
//Switch 'rightBucket' and 'leftBucket' to move from left to right
moveSelectedOptions(selectedIDs, rightBucket, leftBucket, '--None--');
//Sort the resultant options in the left bucket
sortSelect(leftBucket);
Great script!! I do have a question. How do I reference the value of an item in the left bucket. What I want to do is step through the left bucket and move only certain one to the right based on a dynamic condition. I have tried:
selectedOptions[i]
selectedOptions[i].value
selectedOptions.value[i]
Any ideas??
Phil
You should just have to modify the ‘for’ loop to be something like this…
//Check for the item to add here based on sys_id
if(selectedOptions[i].value == 'sys_id_value_of_item'){
//Or check for item here based on display value
//if(selectedOptions[i].text == 'display_value_of_item'){
selectedIDs[index] = i;
index++;
}
}
Mark,
Thanks for this script. This has helped me out a great deal. I have one issue I can’t figure out though. I am using an onChange client Script to move the List items from List Collector 2 when an item in List Collector 1 is changed. the onChange event occurs even when simply clicking in the list, not necessarily when moving an item from left/right or right/left. Therefore my script runs prematurely. Comparing oldValue to newValue doesn’t appear to be worthwhile because oldValue is always empty. Is there a way to see previous list prior to the onChange? Or is there a way to only fire the onChange event when an item is really moved?
Thanks!
Hey Chris. Unfortunately I’m not aware of a way around that. That actually sounds like a bug to me though. The onChange event shouldn’t be triggering unless an item is moved from one side to the other. I think you’ll have to open that one with Service-now support.
Hi Mark,
Very useful script !..
Do you know of a way to modify or remove the add / remove labels from a catalog list collector ?
There’s not really a good way to change this for single variables/items because it would require a client script with easy access to those labels. Neither of those labels have a DOM ID so you could use a client script hack and modify them but that’s probably not a good (or simple) solution.
The simplest way of changing them would be a global setting for ALL slushbuckets in the system. You can just go to ‘System UI->Messages’ and search for the messages with keys of ‘uppercase_add’ and ‘Remove’ and change the associated ‘Message’ values.
Just wondering where the “moveSelectedOptions” function is hiding? I was trying to figure out why the “–None–” item is not being removed from the right bucket as I move stuff over from the left (I swapped the left/right variables in the function call). I added the check for a particular set of values in the left bucket and move them over if they exist instead of moving all items over.
//check for items here based on display value
if((selectedOptions[i].text.toLowerCase() == 'string1')||(selectedOptions[i].text.toLowerCase() == 'string2')){
selectedIDs[index] = i;
index++;
}
}
moveSelectedOptions(selectedIDs, leftBucket, rightBucket,'--None--');
sortSelect(rightBucket);
You can dig into the code by using the script panel in a dom inspector. I use firebug most of the time. You can search through any client scripts loaded for a given page. You should be able to find the ‘moveSelectedOptions’ function by searching for ‘function moveSelectedOptions’ from the script panel in firebug.
As to why it’s not removing the ‘–None–‘ value, the system adds that after the fact any time the right slushbucket ends up empty as a result of the move. I’m not sure why you would want to change that behavior, but you could add “rightBucket.options.length = ‘0’;” to the end of your script to wipe out the ‘–None–‘ value.
The problem is “–None–” is still in the right bucket list when I move over 2 items into the right from the left. The catalog item starts off with 10 items in the left bucket list and I have an onLoad script to pre-populate the right bucket with 2 of those items. I end up with 3 items in the right bucket once I run my code above: “–None–” and the 2 default items I need over there. I added rightBucket.options.length = ’0′; before the move and it is working OK now.
Thanks
Slightly more error-checked:
rightBucket.options.length = '0';
}
Mark,
How are the values for the options stored? I’m trying to take information from a form and populate the right side of the list with the results I get from a previous query. For example: I am having a user pick a group, getting the group members and trying to populate the list collector(sys_user list collector) with the members. Then the user can pick which members to add/remove and then we are passing the updated list back to automate the update of AD. The part I am having issues with is just populating the right column of the list collector with the options from the previous query.
It’s stored as a comma-separated list of sys_ids. If you’re trying to manipulate it with a client script you have to construct a choice list and place it in the correct side of the slush bucket though. Each side acts like its own choice list dropdown.
I was trying to use this to build a “manage your own group memberships” catalog item. The idea being a list of groups you can pick on the left side (all the groups in our system), and a list of groups you’re currently a member of on the right. My problem: the list of groups far exceeds the quantity actually listed in the Left side of the slush bucket. I’m not sure if there’s a clever work around, but it looks like this will only work if the number of options is less than the 100 record display limit on slushbucket sides.
You’re right. You could probably come up with a clever way to query for the groups the user was a member of and just manually add them to the right-side via client script. I’m just not sure if you’d end up with duplicate groups coming over or not that way. You might have to add to the right and then remove from the left via script to avoid any conflict.
This is a great article, but my situation is a little different. I’ve got a lookup table with a list field in it referencing the cmdb_ci_appl table. On a catalog item I have a list collector variable referencing the same table. I have an onChange client script that wants to set the variable list collector with the contents of the lookup table list field. It’s not populating the right-side of the list collector. But I have an alert set up as a debug tool and the sys_ids of the applications in the list field are displayed in the alert. Any thoughts on how to get the list collector variable to show the correct contents from the lookup table list field?
The above script is working fine whileusing it in a client script but throws an exception while using it in a ui script. If you are facing a similar issue kindly help.
Hi Mark, any idea how to clear any values in the Search window of a List Collector variable via script? We have a record producer with a List Collector variable on it. A user might enter a value to search on in the List Collector variable, in the Search box. Then depending on what the user does elsewhere on the form, the List Collector variable is sometimes either hidden or made visible again.
Whenever the List Collector variable is hidden, we clear all values from the right column (which is working fine thanks to your scripts), but if the user makes List Collector variable reappear, anything they had in the Search box for previously in the List Collector is still there. Ideally, anytime we hide the List Collector variable, we’d like to clear any values from the search box at the same time, so that if they do come back to the List Collector variable, they get a fresh start, as if they’d never been there before.
Any thoughts?
You should be able to do this by clearing out the HTML element and triggering the ‘keyup’ event like this…
$('test_sys_user').value = '';
$('test_sys_user').onkeyup();
Hello Mr. Guru,
I am running a Eureka Instance and am trying to get 1 record from the left bucket to the right. I have the set of code wrapped in a try – catch and it throws an error for this line moveSelectedOptions(moveSelectedOptions(selectedIDs,leftBucket, rightBucket, ‘–None–‘);. I know this is an older post and I am not sure if functions have changed over time. Any help would be appreciated.
Thx,
Nate
It looks like ServiceNow has changed the function calls some. You can try replacing the final chunk of the code snippet above with this line and that should help.
moveOptionAndSort(rightBucket, leftBucket, ‘–None–‘, selectedIDs, ‘–None–‘);
I have taken the code from above and replaced what was needed. I am also setting the selectedIDs array with static values for testing purposes. Here is a very simplified version. I cannot get it to transfer any values from the left to the right.
Thanks for all the great help,
Nate
function setBucket(){
try{
var varName = ‘u_related_request’;
var leftBucket = gel(varName + ‘_select_0’);
var rightBucket = gel(varName + ‘_select_1’);
var selectedIDs = new Array();
var index = 0;
selectedIDs[0]=1;
selectedIDs[1]=2;
//Switch ‘rightBucket’ and ‘leftBucket’ to move from left to right
moveOptionAndSort(rightBucket, leftBucket, ‘–None–’, selectedIDs, ‘–None–’);
}catch(e){alert(e);}
}
I did find this in the DOM scripting which means the function is there:
function moveOptionAndSort(
sourceSelect,
targetSelect,
keepSourceLabel,
unmovableSourceValues,
keepTargetLabel) {
moveOption(sourceSelect, targetSelect, keepSourceLabel, unmovableSourceValues, keepTargetLabel, null, null, sortSupported(targetSelect));
}
Mr. Guru,
Here is the proposed solution that my team helped me come up with. Not sure if others might find this useful.
It takes in a sysID and the Req# from the URL and prepopulates the right bucket with that value. Not sure how to post the script in format sorry.
If you think this solution would propose any issues please let me know.
Thanks,
Nate
var reqNumber;
function onLoad() {
var reqNumber2 = getParmVal(‘sysparm_risk’);
if(reqNumber2){
reqNumber = reqNumber2.split(‘,’);
setBucket();
}
}
function setBucket() {
//Type appropriate comment here, and begin script below
try{
var varName = ‘u_related_request’;
var rightBucket = gel(varName + ‘_select_1’);
var option = document.createElement(“option”);
option.value = reqNumber[0];
option.text = reqNumber[1];
rightBucket.add(option);
var selectedOptions = rightBucket.options;
}catch(e){alert(e);}
}
function getParmVal(name) {
name = name.replace(/[\[]/,”\\\[“).replace(/[\]]/,”\\\]”);
var regexS = “[\\?&]”+name+”=([^&#]*)”;
var regex = new RegExp(regexS);
var results = regex.exec( window.location.href );
if(results == null){
return “”;
}
else{
return unescape(results[1]);
}
}
Hello, I’ve used the script for many features over the years; however it seems to have broken in Fuji as well, even after adjusting the new function call ‘moveOptionAndSort’. Any ideas?
Hi Mark,
Is there any way we can do this in a workflow? I need to move all the available option from left to right on a task activity in a workflow for the variable: “Variables On Task Form”. As this is a client side script, is there any business side script?
Kind regards,
Sourabh Dhaygude
There’s no way to do this that I’m aware of.
I couldn’t get it to work by passing the IDs, certainly not in Geneva. So I had to do things a round about way. This is what I used if I know the sys_id of the left bucket value and wanted to move to the right bucket. I haven’t tested this extensively yet, but I’ve add the option to look up a missing value, add it and then move it across if needed. parseResponse being the callback from glide ajax.
var answer = response.responseXML.documentElement.getAttribute("answer");
var ans_arr = answer.split(",");
for(var i = 0; i < ans_arr.length; i++){
if(jQuery('#services_select_0 option[value="'+ans_arr[i]+'"]')){
jQuery('#services_select_0 option[value="'+ans_arr[i]+'"]').attr("selected", "selected");
}
else{
//Add missing option then move it across.
var gBS = new GlideRecord("cmdb_ci_service");
if(gBS.get(ans_arr[i])){
jQuery('#services_select_0').append(jQuery("", {
value: ans_arr[i],
text: gBS.name,
selected: "selected"
}));
}
}
}
moveOptionAndSort(gel('services_select_0'),gel('services_select_1'), '--None--', [], '--None--');
I’ve been running into an issue while running this code. For some reason, the function is running too fast and instead of pulling over everything from the avaiable column, its grabbing the ‘Loading’ text that appears while the list collector is loading. Do you know a way to have this function wait till the list collector is fully loaded?
Figured it out. I just added a 2 sec timeout to give the page time to load.
does this work any different if it was in a scoped app? I have this in a scoped app and the AJAX script is not be called at all.
Has this script been updated to work with the Service Portal?
This script will not work in Service Portal since the behavior of list collector in the default view and Service Portal is different. There are no left and right buckets in Service Portal’s list collector.
Did anyone figure out on how to make this work in Service Portal?
Thanks in advance.
Hi Mark,
I am trying to copy RITM and have few list collector variables.Values are being copied but getting error” Unhandled exception in GlideAjax”.
Have tried steps mentioned in KB article ServiceNow KB: Unable to set the value of a list collector using setValue() (KB0622779)
Also used try & catch method.but still no luck.
Any suggesstion?
we are on Jakarta patch 6a
Hi Mark,
How can we achieve the same functionality in Service Portal?
Thanks,