In the time I’ve been working with ServiceNow, I’ve seen a lot of people using Script Includes to develop code that, in theory, will be reusable. This is a great thing. However, if you don’t pay attention, the number of script includes quickly becomes overwhelming and you loose track of what you (or someone else) has developed. As a result, its not uncommon to have numerous routines that essentially perform the same set of functionality, but because they were unknown by another developer in the system, it went un-reused.
What I’ve found very useful is to put some structure around the creation of your Script Includes to encourage reuse and make it much easier for other developers to find routines that could help them. First, I’ll highlight what a typical Script Include looks like and then transform that into a structure that allows for both server-side and client-side calls to be made to a common library of functions.
The typical Script Include looks something like this:
Name: MyGreatFunction
Script:
function MyGreatFunction(myVar) {
// do something interesting
return some_value;
}
In this case, every script include is defined by a single function by the same name.
To make this more useful, we are going to use functionality built into ServiceNow to create a Script Include that can contain multiple, callable functions. To do this, we will use the Class.create function to encapsulate a set of functions that have related functionality. Using our example above, the new Script Include looks like:
Name: MyGreatFunctionLibrary
Script:
var MyGreatFunctionLibrary = Class.create();
MyGreatFunctionLibrary.prototype = {
initialize: function() {
},
MyGreatFunction: function(myVar) {
// do something interesting
return some_value;
},
type: ‘MyGreatFunctionLibrary’
};
To call this new function, we use the following syntax:
var myVar = new MyGreatFunctionLibrary().MyGreatFunction(‘some_value’);
As you can see, we haven’t changed much, but now we have a way to group similar functionality together, which also means we can more easily find functions that we are looking for. The next step is to make sure that each and every function is documented. I use a pretty simple format to ensure that anyone browsing through the library looking for a function for their purposes can quickly understand the functions purpose, parameters and values being returned. For our example, this might look something like:
//*****
//* Function: MyGreatFunction
//* Purpose : Perform some useful and interesting action
//* @param : {string} myVar – The value that I’m going to act upon
//* @return : {string} some_value that I’ve calulated
//*****
Now that we have a library that can be used for server-side functionality (particularly if we have GlideSystem calls in the function), lets look at how we can add to this to make it callable from the client side. As we know, I can’t call a Script Include directly from a client-side routine that has GlideSystem calls in it. However, I can make an Ajax call from my client-side routine and execute the same Script Include that I just created. To do this, we are going to create a parallel Script Include library who’s only responsibility will be to handle the incoming Ajax call and forward that call onto our function library above.
To keep this manageable, when we create our new Script Include library, we will simply append the word Ajax to existing library name to indicate its purpose. Using our example, the new Script Include will be called MyGreatFunctionAjaxLibrary. This will be setup very similar to the above library with one addition. We will now be extending the ServiceNow Ajax processor to automatically add that capability to our routine. Our Ajax library starts to look like:
Name: MyGreatFunctionAjaxLibrary
Script:
//*****
//* Function: MyGreatFunction
//* Purpose : Perform some useful and interesting action
//* Available to client scripts call using:
//* var ga = new GlideAjax(“MyGreatFunctionAjaxLibrary”);
//* ga.addParam(“sysparm_name”, “MyGreatFunction”);
//* ga.addParam(“sysparm_SomeValue”, ‘value_to_be_processed’);
//*****
var MyGreatFunctionAjaxLibrary = Class.create();
MyGreatFunctionAjaxLibrary.prototype = Object.extendsObject(AbstractAjaxProcessor, {
MyGreatFunction: function() {
var answer = new MyGreatFunctionLibrary().MyGreatFunction(this.getParameter(‘sysparm_SomeValue’));
return answer;
},
type: ‘MyGreatFunctionAjaxLibrary’;
});
There are a couple things to note here. What is not shown is that this Script Include must have the Client Callable option set for the Ajax calls to work. Second is the AbstractAjaxProcessor which allows us to make Ajax calls. Finally is the method of calling this function. You see that we are not passing in a parameter on the function call, but rather as a sysparm value. The client side of this call looks like:
var ga = new GlideAjax(‘MyGreatFunctionAjaxLibrary’);
ga.addParam(‘sysparm_name’, ‘MyGreatFunction’);
ga.addParam(‘sysparm_SomeValue’, ‘some_value’);
From this point, we can either make a getXML or a getXMLWait call from the client. The getXML function makes an asynchronous call, which is the preferred method as it does not stop other processing on the client. However, there are situations where getXMLWait is required since the processing of multiple results my require they be done in a particular sequence.
The getXML code would look like:
ga.getXML(processResult);
function processResult(response) {
var answer = response.responseXML.documentElement.getAttribute(‘answer’);
// process answer
}
The getXML wait code would like like:
ga.getXMLWait();
var myResult = ga.getAnswer();
By adopting this approach and grouping functions that operate on common tables (i.e. sys_user_group), it can save you many headaches in the future by allowing for better reuse opportunities and easier testing and maintenance.
You must log in to post a comment.