Skip navigation

Developer Community

1 Post authored by: Paul Morris

ServiceNow is a fantastic platform that is easy to learn - but hard to master. Despite having a thriving, friendly online community to ask for help, it can be very daunting as a beginner when you are enthusiastically bombarded with multiple solutions. You finally get a solution that seems to make sense, and seems to work - when an expert with even more points and badges tells you that what you are doing "is not best practice". You're then provided with 100 lines of code, that need to be added in multiple different places in the system, that all need to link up together somehow It's all very confusing and you don't understand any of it! And yes, I'm talking about GlideAjax.

 

Rarely a day goes by when someone isn't reaching out for help with Client Scripts. It is very easy to get a value from any table in ServiceNow from business rules and Script Includes, but Client Scripts are so much harder! The API is similar - yet different. It's hard to know what functions work on both client side and server side. You're suddenly told not to use GlideRecord Queries - or that you must have a callback method. The next developer will tell you that you must use GlideAjax and write lines and lines of code. But how - and why?

 

You finally get a grasp of the code, after 10 posts back and forth through 5 different people in 3 different time zones. You've got your Client Script, you've got your Script Include - and it finally works! That is until you realize your original requirement won't do exactly what your boss wants. You have no idea how and where to change the code and in the process of it your code doesn't work at all anymore! You wish you understood how you got there in the first place.

 

Well, you're in luck. Today I am going to go through my process of writing GlideAjax scripts, which I have learned from years of writing Client Scripts and GlideAjax Script Includes for customers and helping ServiceNow community members. I will show you the order I write them in and compartmentalize them - all testable along the way - and leave you with a library to reuse in future. I highly recommend installing Xplore in your instance before proceeding - however, I will also show you how OOB tools can be used.

 

  1. Proof of concept your Client Script (with getReference callback)
  2. Create a testable GlideAjax Script Include
  3. Refactor & Bring it all together
  4. Make your existing GlideAjax scripts reusable (Part 2)

 

Proof of concept your Client Script (with getReference callback)

Let's refactor an established OOB Client Script to be GlideAjax - (BP) Set Location to User. Add the Location field to the Incident form, under the Caller field, if it is not already present.

There is nothing wrong with using getReference as a quick way to setup a proof of concept for a requirement. See the client script code below.

 

function onChange(control, oldValue, newValue, isLoading) {
   if (isLoading)
      return;

   if (newValue == '') {
      g_form.setValue('location', '');
      return;
   }

   if (!g_form.getControl('location'))
      return;

   var caller = g_form.getReference('caller_id', setLocation);
}

function setLocation(caller) {
   if (caller)
       g_form.setValue('location', caller.location);
}

    

Create a testable GlideAjax Script Include
Navigate to "System Definition > Script Includes" and click "New". Populate the 'Name' field with something meaningful (like UserAjaxUtil) and click the 'Client callable' checkbox. This will automatically add the code to extend your script from AbstractAjaxProcessor, so you'll be able to call it from your Client Script. Save the record.

 

Separate Logic from Input
Create two functions in your Script Include as shown below. The golden rule of programming is that a complex problem is just a many simple problems that you need to solve at the same time. So break everything down into its problems! We have two problems to solve here:

  • Get data to and from the form
  • Do something with the data

As a first step, I like to create separate functions for your input from the client and your server side logic, so it becomes testable with different input parameters.

This is the pattern I use for all my GlideAjax scripts.

 

var UserAjaxUtil = Class.create();
UserAjaxUtil.prototype = Object.extendsObject(AbstractAjaxProcessor, {

     ajaxClientDataHandler: function() {
          //Get data from the form
          var gformData1 = this.getParameter('sysparm_parm1');
          //Setup data to return to form
          var answer={};
          //Do server side stuff
          answer['location'] = this.doServerSideStuff(gformData1);
          //Encode data to send back to the form
          return new JSON().encode(answer); 
     },

     doServerSideStuff: function() {
          //Put your logic here
     },

    type: 'UserAjaxUtil'
});

 

Now, let's put our logic into the doServideStuff() function

 

doServerSideStuff: function(userUID) {
     var grUser = new GlideRecordSecure('sys_user');
     if (grUser.get(userUID)) {
          return grUser.getValue('u_location');
     }
},

 

Notice that I have used GlideRecordSecure. Whenever you expose API to the client side, you want to ensure it enforces ACL's - otherwise you are introducing a security hole into your system.
Now, your function is testable using any given user.

 

Now you can call this doServerSideStuff() function using your favorite code testing tool.

 

var userAjaxUtil = new UserAjaxUtil();
userAjaxUtil.doServerSideStuff(gs.getUserID());

 

Output

2c22f8536f541200bbf707574f3ee44f

    

This way, we can test our logic is sound before we call the script from the Client Side and just 'hope for the best'.

 

Now you can simulate values that the client would be sending the Script Include. You can also write all the appropriate Unit Tests if you are doing Automated Testing.

Let's write the ajax input function now too. The whole code will look like this:

 

var UserAjaxUtil = Class.create();  
UserAjaxUtil.prototype = Object.extendsObject(AbstractAjaxProcessor, {  
  
     ajaxClientDataHandler: function() {  
          //Get data from the form
          var gformData1 = this.getParameter('sysparm_parm1');
          //Setup data to return to form
          var answer={};
          //Do server side stuff
          answer['location'] = this.doServerSideStuff(gformData1);
          //Encode data to send back to the form
          return new JSON().encode(answer); 
     },  
  
     doServerSideStuff: function(userUID) {  
          var grUser = new GlideRecordSecure('sys_user');  
          if (grUser.get(userUID)) {  
               return grUser.getValue('location');  
          }
     },  
  
    type: 'UserAjaxUtil'  
});  

 

Refactor & Bring it all together

Next up, we will need to alter our original onChange Client Script.

 

function onChange(control, oldValue, newValue, isLoading) {
   if (isLoading)
      return;


   if (newValue == '') {
      g_form.setValue('location', '');
      return;
   }


   if (!g_form.getControl('location'))
      return;

     var ga = new GlideAjax('UserAjaxUtil'); //Name of the Ajax Script Inclide
     ga.addParam('sysparm_name','ajaxClientDataHandler'); //Method to call
     ga.addParam('sysparm_parm1',newValue); //Parm1
     ga.getXML(userCallback);
}


function userCallback(response) {
     var answer = response.responseXML.documentElement.getAttribute("answer");
     answer = answer.evalJSON(); 
     g_form.addInfoMessage(answer.location);
     setLocation(answer);
}


function setLocation(caller) {
   if (caller)
       g_form.setValue('location', caller.location);
}

 

You can see below that the old Line of code has been commented out and replaced with the GlideAjax code. This is only for instructional purposes - it is generally a bad idea to comment out code with no explanation. If it's not needed - it should be removed. ServiceNow has Version Control via Update Sets, so you can always go back and look at past state.

 

Make your existing GlideAjax scripts reusable

You've now been given a procedure for writing GlideAjax that hopefully makes it a much more enjoyable process. You're happy that you've learned something new and that you've been able to implement a requirement using Best Practice. That is until your boss gives you a new requirement. He wants the Callers job title shown on the screen as well. Never fear - we have already written the foundations to make this a whole lot easier!

 

Part 2 Coming Soon! Feedback Welcome

------------
Please mark response with a Like, Helpful or Correct :)

Filter Blog

By date: By tag: