Announcing the Global SNUG Board of Directors. Learn more here

Help
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Goran WitchDoc
ServiceNow Employee
ServiceNow Employee

For some time ago I sat and were fouling around with how to populate fields on a catalog item. The thing is that we have our standard changes as catalog items. And depending if it was a call, incident, request etc. that was the source for creating this standard change, different fields should tag along to the standard change and populate some variables on the form. For this I would like to only have one client script handling this and make it as dynamic and easy to add/remove fields which should tag along. I wanted only one place to add that information and not need to head to both my script include and the client script to do so.

So this is what I came up with:

First this the for example one UI action I use to get into the catalog from a record. In this case incident:

//Update saves incident before going to the catalog homepage

current.update();

gs.addInfoMessage('You will need to navigate back to incident ' + current.number + ' upon completion');

//Getting the table the record is from and the sysID and separating them with a "," so I can easy split them up later

var info = current.sys_class_name + ',' + current.sys_id;

var url = "catalog_home.do?sysparm_view=catalog_default&sysparm_processing_hint=" + info;

//And into the catalog we go

action.setRedirectURL(url);

Now, a little heads up. As you can see on the code above, I'm using the parameter "sysparm_processing_hint". This is a parameter that follow with us the whole way when we click through our catalog. I haven't found any other use for it and no documentation for it. But I needed something to tag along the info of the source. But know about the danger it might have using stuff like this. Making my own custom "sysparm_info_to_me" would sadly only tag along to the catalog, but then disappear directly when I clicked on a category or an item.

So, we get to the item and the onLoad Catalog client script kicks in. first part of the client script looks like this:

function onLoad()

{

  //Get the parameter if the std. change is created from an record.

//Parameter contains both the tablename and sys_id of the record. Seperated with a ,

  var infosource = getParmVal('sysparm_processing_hint');

//If the parameter exists send it to a script include which returns which fields to populate and with what data

  if (infosource) {

  g_form.setValue('sysparmprocessinghint',infosource);

  var ga = new GlideAjax('getSourceInfo');

  ga.addParam('sysparm_name','getInfo');

  ga.addParam('sysparm_process', infosource);

  ga.getXML(handleAnswer);

  }

Pretty much the standard GlideAjax call. In the beginning you can see that we get the parameter and if that exist we do the call and also send that info with as the parameter sysparm_process. And when we get the result back, the function "handleAnswer" takes care of that. We will get back to it later, but lets us look at the script include.

var getSourceInfo = Class.create();

getSourceInfo.prototype = Object.extendsObject(AbstractAjaxProcessor, {

  //Return fields to catalog item form

  getInfo: function() {

  var fromSysparm = this.getParameter('sysparm_process');

//Splits the data from the parameter. it looks like TABLE_NAME,SYS_ID

  var infoSource = fromSysparm.split(',');

  var toReturn = {};

//Getting the record from correct table

  var gr = new GlideRecord(infoSource[0]);

  gr.get(infoSource[1]);

//Going through the tables is can be and depending on the table, putting in different properties in the object.

  if (infoSource[0] == 'sc_req_item'){

  toReturn.requested_for = gr.request.requested_for.toString();

  toReturn.comments = gr.description.toString();

  if(gr.u_contact_person != '')

  toReturn.requested_by = gr.u_contact_person.toString();

  if(gr.u_alternative_mailaddress != '')

  toReturn.alternative_address = gr.u_alternative_mailaddress.toString();

  }

  else if(infoSource[0] == 'incident'){

  toReturn.requested_for = gr.assigned_to.toString();

  }

  else if(infoSource[0] == 'new_call'){

  toReturn.requested_for = gr.caller.toString();

  toReturn.comments = gr.description.toString();

  toReturn.short_description = gr.short_description.toString();

  if(gr.u_alternative_mailaddress != '')

  toReturn.alternative_address = gr.u_alternative_mailaddress.toString();

  }

//Returning the object as a JSON

  return JSON.stringify(toReturn);

  },

  type: 'getSourceInfo'

});

So the Script include takes the tablename and sys_id and fetches the record. then depending on which table it's, it put different properties into the object "toReturn" which in the end is the object that the script include returns. To get this all to work, it's VERY important that the objects properties has the same name as the variable/field it is going to populate in the client script.

Now lets see what the Catalog client script does with the data the script include returns. It uses the function "handleAnswer" to do this:

function handleAnswer(response){

  var answer = response.responseXML.documentElement.getAttribute("answer");

//Convert the answer to a JSON since it was stringified to a JSON in the script include

  var doJson = JSON.parse(answer);

//this gets all the properties(Which name is identically to the variable their are going to put data in)

//Then the forEach put each value into the correct field.

  Object.getOwnPropertyNames(doJson).forEach(function(val,idx, array){

  g_form.setValue(val,doJson[val]);

  });

}

Here I parse the answer back to a JSON object and then I use the Object.getOwnPropertyNames() - JavaScript | MDN to get all the property names and loop through them and set the correct values. This way, if I want to add another variable to populate, I can just add it in the script include and it will automagically fill in on the form with the client script.

18 Comments