Earl Duque
Administrator

The problem

 

Script Includes in ServiceNow, in a very simplistic explanation, is a server side script that can be called from other server scripts, making them great for re-usability.

 

Client callable script includes in ServiceNow are typically combined with an ServiceNow API method called GlideAjax. It’s a method that handles the actual AJAX part of your script that sends and receives data between the client and the server.

 

Often, it’s easier to think of these things separately, but for ease of use, there’s often times we’d want to combine them.

 

Example of Server Callable Script Includes

 

Script Include:

var My_Functions = Class.create();
My_Functions.prototype = {
    initialize: function() {
    },

	log_info: function(x) {
		gs.info(x);
		return 'success';
	},
	
    type: 'My_Functions'
};


Code that calls script include function:

var y = new My_Functions().log_info('Testing');
  • y would be set to ‘success’
  • ‘Testing’ would be logged to the system (via gs.info())

 

Example of Client Callable Script Includes

 

Script Include (Set Client callable to true):

var My_Functions = Class.create();
My_Functions.prototype = Object.extendsObject(AbstractAjaxProcessor, {
	log_info: function(){
		var results = {};
		var x = this.getParameter('sysparm_x');
		gs.info(x);
		results.message = 'success';
		return JSON.stringify(results);
	},
	
    type: 'My_Functions'
});


Code that calls the script include function:

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

	var ga = new GlideAjax('My_Functions'); 
	ga.addParam('sysparm_name','log_info'); 
	ga.addParam('sysparm_x', 'Testing'); 
	ga.getXML(ResponseFunction); 
	
	function ResponseFunction(response) { 
		var answer = response.responseXML.documentElement.getAttribute("answer"); 
		var results = JSON.parse(answer);
		alert(results.message);
	}
}
  • An alert window would appear with the value of results.message which would be ‘success’
  • ‘Testing’ would be logged to the system (via gs.info())

 

Example of a single combined Script include

 

Script include (note the small changes in bold from the example client-callable script include):

var My_Functions = Class.create();
My_Functions.prototype = Object.extendsObject(AbstractAjaxProcessor, {
	log_info: function(x0){
		var results = {};
		var x = this.getParameter('sysparm_x') || x0;
		gs.info(x);
		results.message = 'success';
		return JSON.stringify(results);
	},
	
    type: 'My_Functions'
});


Because of the small changes:

  • When called from client, it still sets x according to the .getParameter() function
  • When called from server, if passed a parameter, it first passes to the function then gets set to x because of the lack of parameters to retrieve.

 

Presto, a single function with parameters that can now be called either way!

 

Note: Does this blog look familiar? This was originally posted on my personal blog on July 31, 2019. I'm taking down that website but this is still one of my most visited pages years later, so I'm uploading it here so that it doesn't disappear forever. Enjoy! -Earl

7 Comments
Rampriya-S
Kilo Sage

Well-explained, Earl. It is simple and easily understandable. Thank you!

Frantisek Toman
Tera Explorer

Hi Earl,

Great topic. It is common to see copy-pasted pieces of code from non-client-callable to client-callable, which is far from ideal.


There are more solutions to the problem.

To me, the non client-callable is the library of all all reusable functions and the client-callable are just exposing the them to the client. In other words: client-callable should only handle the API (parameters, stringify the return value) add some security and call the server script include that does the business logic.

I think it is more readable. Client-callable has one job, and non-client-callable is the reusable part.

 

What do you think? 

Glitch
Tera Explorer

I used to have a client callable SI that would then call a server side only SI.

Also believe this used to be the "best practice" a few years ago?!

That way the server side script is always invoked with an argument that is passed on through the client side one with a parameter.

It does add the "extra" SI complexity to the solution, but as mentioned by Frantisek, we should try to maintain the server side SI as a set of reusable core tools, and have the client callable SI working somewhat as a service provider.

Dwight S_1
Tera Contributor

Is there any performance cost associated with making a script include client callable?

Jim Myrah
Tera Contributor

I like that you are returning stringified JSON to the client, I still see delimited strings at times.  For server-side I like to return the JSON object which can also be determined based on parameters.

stevesmith
Tera Sage

Had to do this a couple months ago and used this solution. You explain it so well, Earl!

Zuhaib
Tera Contributor