How to populate list collector based on two fields?

shwethanair
Kilo Expert

Hello,

We have a requirement to populate the right side of List collector referencing to Application table with respect to two Select box field choices.

Selectbox - Category : Customer ,                               Selectbox - Category : Vendor

Selectbox - Type : Access Request ,                            Selectbox - Type : Deletion Request

List Collector - Application : A, B , C, D ,                       List Collector - Application : X, Y , Z

The Category and Type are mapped to Type and Category in CMDB application table , hence are pulling the choice values from there. Therefore whenever user chooses Type & Category in the Catalog for the respective mapped application should populate in the right side of list collector.

I have tried writing client script and Script include as follows but its not populating values somehow.

Please let me know where I need to make correction.

Script Include:

var getApplications = Class.create();
getApplications.prototype = Object.extendsObject(AbstractAjaxProcessor, {
selectAppl: function() {
var list = [];
var typ = this.getParameter('sysparm_type');
var ctg = this.getParameter('sysparm_category');
var parm = this.getParameter('sysparm_view');

var jsonArr = [];

var appl = new Gliderecord ('cmdb_ci_web_application');
appl.addQuery('u_type', typ);
appl.addQuery('u_category', ctg);
appl.query();
while(appl.next()){
if(parm == 'portal'){
list.push(appl.name);
}

else if(parm == 'native'){
var obj = {};
obj.name = appl.name;
obj.sys_id = appl.name.toString();
jsonArr.push(obj);
}

}

if(parm == 'portal')
return list.toString();
else
return JSON.stringify(jsonArr);

},

type: 'getApplications'
});

 

Onchange client script :

function onChange(control, oldValue, newValue, isLoading) {
if (isLoading || newValue == '') {
return;
}
g_form.clearValue('select_appli_list');
var ctg = g_form.getValue('category');
var parm = '';
if (window === null)
parm = 'portal';
else
parm = 'native';

var ajax = new GlideAjax('getApplications');
ajax.addParam('sysparm_name', 'selectAppl');
ajax.addParam('sysparm_type', newValue);
ajax.addParam('sysparm_category', ctg);
ajax.addParam('sysparm_view', parm);
ajax.getXML(populateValues);
}

function populateValues(response) {
var answer = response.responseXML.documentElement.getAttribute("answer");
var arr = answer.split('||');

// give here the list collector variable name
if (window === null) {
g_form.setValue('select_appli_list', arr[0]); // Mobile/Portal Compatible

} else {
addItemstoList('select_appli_list', answer); // Native Compatible
}
}
function addItemstoList(listCollector, applList) {

var parser = JSON.parse(applList);

var arrSysId = [];
var arrName = [];
for(var i=0;i<parser.length;i++){
arrName.push(parser[i].name);
arrSysId.push(parser[i].sys_id.toString());
}

var varName = listCollector;
var leftBucket = gel(varName + '_select_0');
var rightBucket = gel(varName + '_select_1');
var rightOptions = leftBucket.options;
var rightIDs = [];
//Remove --None--
for (var k= 0; k < rightOptions.length; k++) {
var value = rightOptions[k].innerHTML;
if (value == '--None--') {
leftBucket.remove(0);
}
}
// Add new options
if (arrName.length > 0) {
var myCIArray = arrName.toString().split(',');
for (var j = 0; j < myCIArray.length; j++) {
addOption(rightBucket, arrSysId[j], myCIArray[j]);
moveSelectedOptions(rightOptions, leftBucket , rightBucket);
sortSelect(rightBucket);
leftBucket.onchange();
}
}

// sort the buckets
sortSelect(rightBucket);
}

1 ACCEPTED SOLUTION

Brad Bowman
Kilo Patron
Kilo Patron

There are a couple of different ways to do this, but going down the path you were on, these scripts will work in Service Portal and the Native UI for any number of records in the table.  The same client script should be used onChange of Category and Type in case the requester populates them out of order.  You can also add a reference qualifier on the List Collector variable so that onLoad, invalid Applications cannot be selected

javascript:"u_category=" + current.variables.category + "^u_type=" + current.variables.type

Client Script, with Isolate script box unchecked

function onChange(control, oldValue, newValue, isLoading) {
 if (isLoading || newValue == '') {
  return;
 }

 g_form.clearValue('select_appli_list');
 var ctg = g_form.getValue('category');
 var typ = g_form.getValue('type');
 if(ctg && typ){
  var parm = '';
  if (window === null)
   parm = 'portal';
  else
   parm = 'native';

  var varName = 'select_appli_list';// name of the list collector variable
  var filterString = 'u_category=' + ctg + '^u_type=' + typ;
  //first reset the filter (left side) based on the 2 variables
  if(parm == 'portal'){
   var myListCollector = g_list.get(varName);
   myListCollector.reset();
   myListCollector.setQuery(filterString);
  }
  else{
   window[varName + 'g_filter'].reset();
   window[varName + 'g_filter'].setQuery(filterString);
   window[varName + 'acRequest'](null);
  }
  //now populate the Service Portal variable 
  if(parm == 'portal'){  
   var ajax = new GlideAjax('getApplications');
   ajax.addParam('sysparm_name', 'selectAppl');
   ajax.addParam('sysparm_type', typ);
   ajax.addParam('sysparm_category', ctg);
   ajax.getXML(populateValues);

   function populateValues(response) {
    var answer = response.responseXML.documentElement.getAttribute("answer");
    var arr = answer.split('||');
    //arr[1] has the sys_id of the applications 
    //arr[0] has the display name of the applications 
    g_form.setValue('select_appli_list', arr[1], arr[0]); 
   }
  }
  else{
   //or move all selections from the left side to right side
   //wrapped in a timeout to give the filter time to reset
   //adjust the number (3000) lower if the move is waiting too long after the new choices are loaded, or higher if the move is attempted before the filter is done loading - so the incorrect values are moved to the right side
   window.setTimeout(function(){
    var leftBucket = gel(varName + '_select_0');
    var rightBucket = gel(varName + '_select_1');
    var selectedOptions = leftBucket.options;
    var selectedIDs = new Array();
    var index = 0;
    for(var i = 0; i < selectedOptions.length; i++){
     selectedIDs[index] = i;
     index++;
    }
    rightBucket.options.length = '0';
    moveSelectedOptions(selectedIDs, leftBucket, rightBucket);
    sortSelect(rightBucket);
   }, 3000);
  }
 }
}  

Script Include, with Client callable box checked

var getApplications = Class.create();
getApplications.prototype = Object.extendsObject(AbstractAjaxProcessor, { 
 
selectAppl: function() {
 var name_arr = []; 
 var sys_id_arr = []; 
 var typ = this.getParameter('sysparm_type');
 var ctg = this.getParameter('sysparm_category');
 var appl = new GlideRecord ('cmdb_ci_web_application');
 appl.addQuery('u_type', typ);
 appl.addQuery('u_category', ctg);
 appl.query();
 while(appl.next()){
  name_arr.push(appl.name.toString()); 
  sys_id_arr.push(appl.sys_id.toString());
 }
 return name_arr.toString() + '||' + sys_id_arr.toString();
 
},
type: 'getApplications'
});

 

View solution in original post

7 REPLIES 7

Brad Bowman
Kilo Patron
Kilo Patron

Are you using the Service Portal, native Service Catalog, or both?  Change your object lines in the script include to

obj.name = appl.name.toString();
obj.sys_id = appl.toString();

This is assuming the List Collector variable also references the cmdb_ci_web_application table.  The other important thing here is that the left side of the List must contain the choices to be moved to the right side before the move, and they have to be within the first results returned (default is 100).  I can't immediately tell from your client script if you are resetting the filter before moving. Both scripts are a lot more complicated than they need to be if you're not using the Service Portal.

Hello Brad,

Thanks for the quick reply.

Yes we will be using both Portal and native to submit the request. I have already tried the changes you had asked to but there is no changes I could observe therefore I was trying with this as my Name field in Application table is already a string field.

Thanks,

Shwetha Nair

Brad Bowman
Kilo Patron
Kilo Patron

It's best to use toString() when assigning objects just to be safe.  Does the List Collector variable reference the cmdb_ci_web_application table?  If not in your Script Include you have to query the table it does reference for the application names returned by the first query to return the sys_ids to the client script.  In your client script alert on answer right after the var answer line to see if you are getting the results from the server script that you expect.  Change the next line to

var arr = answer.split(',');

as the array will be comma-separated in both the portal and native paths.  When testing this in native, do you have more than 100 values in this referenced table, and are the records in the answer shown in the left box without filtering or searching on anything?

The script include and client script need further changes, but I can't guide you on that until the above questions are answered.

Does the List Collector variable reference the cmdb_ci_web_application table? - YES

When testing this in native, do you have more than 100 values in this referenced table, and are the records in the answer shown in the left box without filtering or searching on anything? - YES