Join the #BuildWithBuildAgent Challenge! Get recognized, earn exclusive swag, and inspire the ServiceNow Community with what you can build using Build Agent.  Join the Challenge.

Service Catalog variable cleared after request submission.

Damian17
Giga Contributor

Dear ServiceNow Specialists, 

I faced the issue with the ServicePortal form. What I wanted is to based on one reference field from cmdb_ci_appl table, auto-populate values in variables on the form. 
I used Script Include to gather values and Catalog Client Script to populate them.

The functionality works fine, however, when the form is submitted, values which reference sys_choice table are not saved. If I change the value in these fields, it will save it to a variable. If I don't do anything with them, they will be saved as empty on the requested item. 

With Script Include, I'm feeding the Catalog Client Script with Value of the sys_choice record and Label of it. Both Scripts below.

Script Include:

var appl_data;

function onChange(control, oldValue, newValue, isLoading) {
	
	g_form.setValue('var_category','','');
		g_form.setValue('version','');
	
   if (isLoading) {
      return;
   }
	
	// new GlideAjax object referencing name of AJAX script include 
var ga = new GlideAjax("ApplicationPortfolioReview"); 
// add name parameter to define which function we want to call 
// method name in script include will be getFavorites
ga.addParam("sysparm_name","getApplData");
ga.addParam("sysparm_bs", newValue);

// submit request to server, call ajaxResponse function with server response
 
ga.getXML(ajaxResponse);
 
	function ajaxResponse(serverResponse) {

	  // get result element and attributes
	  var result = serverResponse.responseXML.getElementsByTagName("result");
		console.log(result);
	  var message = result[0].getAttribute("message");

	  //check for message attribute and alert user
	 // if(message) alert(message);

	  // get application data 
	  appl_data = serverResponse.responseXML.getElementsByTagName("result");
      if (appl_data.length>1) {
		  
		g_form.setValue('var_lifecycle_status', appl_data[1].getAttribute("install_status_value"), appl_data[1].getAttribute("install_status_label"));
		g_form.setValue('var_operational_status', appl_data[1].getAttribute("operational_status_value"), appl_data[1].getAttribute("operational_status_label"));
		g_form.setValue('var_manufacturer', appl_data[1].getAttribute("manufacturer_value"), appl_data[1].getAttribute("manufacturer_label"));
		g_form.setValue('var_owned_by', appl_data[1].getAttribute("system_owner_value"), appl_data[1].getAttribute("system_owner_label"));
		g_form.setValue('var_managed_by', appl_data[1].getAttribute("system_admin_value"), appl_data[1].getAttribute("system_admin_label"));
		g_form.setValue('var_version', appl_data[1].getAttribute("version"));
		alert('operational_status_value: ' + appl_data[1].getAttribute("operational_status_value") +'\ninstall_status_value: ' +appl_data[1].getAttribute("install_status_value"));
	  }
		
	}
}

Catalog Client Script:

var ApplicationPortfolioReview = Class.create();
ApplicationPortfolioReview.prototype = Object.extendsObject(AbstractAjaxProcessor, {
	getApplData: function() { // build new response xml element for result
		
		result.setAttribute("message", "returning users for ");
		
		//table to query: cmdb_ci_appl
		//param = sys_id of program group
		//return ...
		var appl_sys_id = this.getParameter('sysparm_bs');
		
		if (!appl_sys_id) {
			return false;
		}
		
		var AP = new GlideRecord('cmdb_ci_appl');
		
		if (!AP.get(appl_sys_id)) {
			return false;
		}
		
		var result = this.newItem("result");
		result.setAttribute("message", "returning users for " + appl_sys_id);
		
		this._addDetails(AP);
		
	},
	// all items are returned to the client through the inherited methods of AbstractAjaxProcessor
	_addDetails: function(AP) {
		var appl_data = this.newItem("result");
		appl_data.setAttribute("install_status_label", AP.install_status.getDisplayValue());
		appl_data.setAttribute("install_status_value", AP.install_status);
		appl_data.setAttribute("operational_status_label", AP.operational_status.getDisplayValue());
		appl_data.setAttribute("operational_status_value", AP.operational_status);
		appl_data.setAttribute("manufacturer_label", AP.manufacturer.getDisplayValue());
		appl_data.setAttribute("manufacturer_value", AP.manufacturer);
		appl_data.setAttribute("system_owner_label", AP.owned_by.user_name);
		appl_data.setAttribute("system_owner_value", AP.owned_by);
		appl_data.setAttribute("system_admin_label", AP.managed_by.user_name);
		appl_data.setAttribute("system_admin_value", AP.managed_by);
		appl_data.setAttribute("version", AP.version);
	},
	type: 'ApplicationPortfolioReview'
});

Please, help me to troubleshoot this, or point what should I correct.

1 ACCEPTED SOLUTION

Hello Omkar,

I marked your answer as correct, but the true solution, according to best practice, required a little bit different approach. Please, let me explain. 

To auto-populate and keep value in Reference type field to sys_choice table, on Service Portal form you need to gather:

  • Label of the sys_choice record,
  • sys_id of the sys_choice record.

I did it in Script Include by using a query for each of these kinds of fields. They are described as IS and OP

var ApplicationPortfolioReview = Class.create();
ApplicationPortfolioReview.prototype = Object.extendsObject(AbstractAjaxProcessor, {
	getApplData: function() { // build new response xml element for result
		
		result.setAttribute("message", "returning users for ");
		
		//table to query: cmdb_ci_appl
		var appl_sys_id = this.getParameter('sysparm_bs');
		
		if (!appl_sys_id) {
			return false;
		}
		
		var AP = new GlideRecord('cmdb_ci_appl');
		
		if (!AP.get(appl_sys_id)) {
			return false;
		}
		
		//sys_id of recrod from sys_choice table
	var IS = new GlideRecord('sys_choice');
		IS.addEncodedQuery('name=cmdb_ci_appl^element=install_status^inactive=false^value='+AP.install_status);
		IS.query();
		if(!IS.next()){
			return false;
		}
		
		//sys_id of record from sys_choice table
			var OP = new GlideRecord('sys_choice');
		OP.addEncodedQuery('name=cmdb_ci^element=operational_status^inactive=false^value='+AP.install_status);
		OP.query();
		if(!OP.next()){
			return false;
		}
	
		var result = this.newItem("result");
		result.setAttribute("message", "sys_id of CI record " + appl_sys_id);
		
		this._addDetails(AP,OP,IS);
		
	},
	// all items are returned to the client through the inherited methods of AbstractAjaxProcessor
//proper variable feed to the function
	_addDetails: function(AP,OP,IS) {
		
		var appl_data = this.newItem("result");
		
		appl_data.setAttribute("install_status_label", AP.install_status.getDisplayValue());
		appl_data.setAttribute("install_status_value", IS.sys_id);
		appl_data.setAttribute("operational_status_label", AP.operational_status.getDisplayValue());
		appl_data.setAttribute("operational_status_value", OP.sys_id);
		appl_data.setAttribute("manufacturer_label", AP.manufacturer.getDisplayValue());
		appl_data.setAttribute("manufacturer_value", AP.manufacturer);
		appl_data.setAttribute("system_owner_label", AP.owned_by.user_name);
		appl_data.setAttribute("system_owner_value", AP.owned_by);
		appl_data.setAttribute("system_admin_label", AP.managed_by.user_name);
		appl_data.setAttribute("system_admin_value", AP.managed_by);
		appl_data.setAttribute("version", AP.version);
	},
	type: 'ApplicationPortfolioReview'
});

For unknown, at least for me, reason, a reference to sys_choice table require different treatment, because in the example of another Reference type field - manufacturer, feeding it with label and value was enough, no sys_id required. ¯\_(ツ)_/¯

I could use only the sys_id, without using of Label of the record, but in that case, the system was doing its own query on every change of the form to find the Label, and I prefer to do it on my own. I observed this in the browser Network activities, that every time the Catalog Client script was triggered, another query was launched.

That is why, feeding the field only with sys_id will do the job but from the best practices point of view, it is not enough.

* I've noticed, that in my question I described Catalog Client Script as Script Include and vice versa, I'm sorry for the confusion.

I appreciate your input here, cause I was missign this peace of the puzzle, Omkar. 

Sincere, Thank You.

Damian

View solution in original post

6 REPLIES 6

Welcome 🙂

Hello Omkar,

I marked your answer as correct, but the true solution, according to best practice, required a little bit different approach. Please, let me explain. 

To auto-populate and keep value in Reference type field to sys_choice table, on Service Portal form you need to gather:

  • Label of the sys_choice record,
  • sys_id of the sys_choice record.

I did it in Script Include by using a query for each of these kinds of fields. They are described as IS and OP

var ApplicationPortfolioReview = Class.create();
ApplicationPortfolioReview.prototype = Object.extendsObject(AbstractAjaxProcessor, {
	getApplData: function() { // build new response xml element for result
		
		result.setAttribute("message", "returning users for ");
		
		//table to query: cmdb_ci_appl
		var appl_sys_id = this.getParameter('sysparm_bs');
		
		if (!appl_sys_id) {
			return false;
		}
		
		var AP = new GlideRecord('cmdb_ci_appl');
		
		if (!AP.get(appl_sys_id)) {
			return false;
		}
		
		//sys_id of recrod from sys_choice table
	var IS = new GlideRecord('sys_choice');
		IS.addEncodedQuery('name=cmdb_ci_appl^element=install_status^inactive=false^value='+AP.install_status);
		IS.query();
		if(!IS.next()){
			return false;
		}
		
		//sys_id of record from sys_choice table
			var OP = new GlideRecord('sys_choice');
		OP.addEncodedQuery('name=cmdb_ci^element=operational_status^inactive=false^value='+AP.install_status);
		OP.query();
		if(!OP.next()){
			return false;
		}
	
		var result = this.newItem("result");
		result.setAttribute("message", "sys_id of CI record " + appl_sys_id);
		
		this._addDetails(AP,OP,IS);
		
	},
	// all items are returned to the client through the inherited methods of AbstractAjaxProcessor
//proper variable feed to the function
	_addDetails: function(AP,OP,IS) {
		
		var appl_data = this.newItem("result");
		
		appl_data.setAttribute("install_status_label", AP.install_status.getDisplayValue());
		appl_data.setAttribute("install_status_value", IS.sys_id);
		appl_data.setAttribute("operational_status_label", AP.operational_status.getDisplayValue());
		appl_data.setAttribute("operational_status_value", OP.sys_id);
		appl_data.setAttribute("manufacturer_label", AP.manufacturer.getDisplayValue());
		appl_data.setAttribute("manufacturer_value", AP.manufacturer);
		appl_data.setAttribute("system_owner_label", AP.owned_by.user_name);
		appl_data.setAttribute("system_owner_value", AP.owned_by);
		appl_data.setAttribute("system_admin_label", AP.managed_by.user_name);
		appl_data.setAttribute("system_admin_value", AP.managed_by);
		appl_data.setAttribute("version", AP.version);
	},
	type: 'ApplicationPortfolioReview'
});

For unknown, at least for me, reason, a reference to sys_choice table require different treatment, because in the example of another Reference type field - manufacturer, feeding it with label and value was enough, no sys_id required. ¯\_(ツ)_/¯

I could use only the sys_id, without using of Label of the record, but in that case, the system was doing its own query on every change of the form to find the Label, and I prefer to do it on my own. I observed this in the browser Network activities, that every time the Catalog Client script was triggered, another query was launched.

That is why, feeding the field only with sys_id will do the job but from the best practices point of view, it is not enough.

* I've noticed, that in my question I described Catalog Client Script as Script Include and vice versa, I'm sorry for the confusion.

I appreciate your input here, cause I was missign this peace of the puzzle, Omkar. 

Sincere, Thank You.

Damian