Client Side Scripting: Go for GlideAjax (with getXMLAnswer)!
Articles, Blogs, Videos, Podcasts, Share projects - Experiences from the field
Hi there,
Community questions on Client Side scripting to retrieve data, often answers are giving suggestions to use GlideAjax. GlideAjax (with getXMLAnswer) absolutely being the best method for retrieving data Client Side.
Though somehow a lot developers are using techniques like GlideRecord, getReference or getReference with a callback. Obviously, this could be because of someone is new in the ServiceNow eco-system and just hasn't touched on this subject yet. Or it could be the developer is just lazy
. Or could it be that answers and articles on the Community on this subject (and there are loads of them!) are not clear enough or hard to find?
Well, I'll give it a go to explain some basic GlideAjax examples (with getXMLAnswer). In a later article I'll explain our dynamic GlideAjax functionality. Also, I'll add some hints to make the scripting a lot easier.
Client Side Scripting
First, let's explain why GlideAjax is mentioned so often. Why not just use one (1) line of code with GlideRecord getReference? Or five (5) lines of code with GlideRecord? Those are so easy to set up, so why not?!
You might have seen the table below already somewhere (not mine: Paul Morris!). The table is a good visualization of Simplicity versus Efficiency.
| API | Simplicity | Efficiency | Description |
|---|---|---|---|
| GlideRecord getReference | 1st | 5th | - 1 line of code- Poor UX (blocks browser)- Returns entire record |
| GlideRecord | 2nd | 4rd | - ~ 5 lines of code- Poor UX (blocks browser)- Returns entire record |
| GlideRecord getReference(with callback) | 3rd | 3rd | - 5-10 lines of code (with callback)- Best UX (does not block browser)- Returns entire record |
| GlideRecord(with callback) | 4th | 2nd | - ~ 10 lines of code (with callback)- Best UX (does not block browser)- Returns entire record |
| GlideAjax | 5th | 1st | - ~20 lines of code (Client Script + Script Include)- Best UX (does not block browser)- Returns only the data you need |
Bad Practice
Looking at the above table, GlideRecord getReference, and GlideRecord are for sure not done. No explanation needed. Yes, one (line) of code could do, though efficiency-wise a really poor choice. Just don't go this road.
Poor Practice
Looking at the above table, GlideRecord getReference (with callback), and GlideRecord (with callback) are UX wise fine. Though, these still return the entire record. getRefence (with callback) is used a lot, though there is a better way.
Best practice
GlideAjax tops the efficiency chart. Make a habit of using this. So why is GlideAjax actually often not a habit to use? Well simply because developers are not familiar with this, that it takes a lot more lines of code instead of the really simple GlideRecord getReference, that it takes two (2) artifacts (a (Catalog) Client Script, and a Script Include).
Note: Actually I would change "GlideAjax" into "GlideAjax (with getXMLAnswer)". GlideAjax with getXML still would return a whole document. While GlideAjax with getXMLAnswer would only return the exact answer you need. Read about this in one of my previous articles: getXMLAnswer vs getXML.
Later in this article I'll give two (2) hints on how to make life for you as a developer easier, not having to write out all the code over and over. Also in a later article, I'll share our dynamic GlideAjax set up which can potentially be used on every field on every table through your instance without additional maintenance.
GlideAjax examples
1) We would like to retrieve the Phone number of a Caller selected. Phone number should be written to a custom Phone number field on the Incident form (u_phone).
Script Include
Name: getUserPropertiesAjaxClient callable: true
Script:
var getUserPropertiesAjax = Class.create();
getUserPropertiesAjax.prototype = Object.extendsObject(AbstractAjaxProcessor, {
get_phone : function() {
var grUser = new GlideRecord('sys_user');
if(grUser.get(this.getParameter('sysparm_user'))) {
return grUser.getValue('phone');
}
},
type: 'getUserPropertiesAjax'
});
Client Script
Table: IncidentType: onChangeField name: Caller
Script:
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if(isLoading) {
return;
}
if(newValue === '') {
g_form.clearValue('u_phone');
}
var gaPhone = new GlideAjax('getUserPropertiesAjax');
gaPhone.addParam('sysparm_name', 'get_phone');
gaPhone.addParam('sysparm_user', newValue);
gaPhone.getXMLAnswer(_handleResponse);
function _handleResponse(response) {
var answer = response;
g_form.setValue('u_phone', answer);
}
}
2) We would like to retrieve the Location of a Caller selected. Location should be written to the out-of-the-box Location field on the Incident form (location).
Script Include
We'll just add a function "get_location" to the Script Include created earlier.
Script:
var getUserPropertiesAJAX = Class.create();
getUserPropertiesAJAX.prototype = Object.extendsObject(AbstractAjaxProcessor, {
get_phone : function() {
var grUser = new GlideRecord('sys_user');
if(grUser.get(this.getParameter('sysparm_user'))) {
return grUser.getValue('phone');
}
},
get_location : function() {
var grUser = new GlideRecord('sys_user');
if(grUser.get(this.getParameter('sysparm_user'))) {
var answer = {};
answer.value = grUser.getValue('location');
answer.displayValue = grUser.getDisplayValue('location');
return JSON.stringify(answer);
}
},
type: 'getUserPropertiesAJAX'
});
Note: Instead of just returning "return grUser.getValue('location')", we are actually returning the getValue and the getDisplayValue. This is because g_form.setValue(), for a Reference field expects the value AND the display value. If only returning the value (the sys_id), an additional Server call will be performed (and the efficiency reason for why performing GlideAjax would then actually be lost).
Client Script
Table: IncidentType: onChangeField name: Caller
Script:
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if(isLoading) {
return;
}
if(newValue === '') {
g_form.clearValue('location');
}
var gaLocation = new GlideAjax('getUserPropertiesAJAX');
gaLocation.addParam('sysparm_name', 'get_location');
gaLocation.addParam('sysparm_user', newValue);
gaLocation.getXMLAnswer(_handleResponse);
function _handleResponse(response) {
var answer = JSON.parse(response);
g_form.setValue('location', answer.value, answer.displayValue);
}
}
Note: When using the Script Editor, notice the information on g_form.setValue:
Making life easier
So is there anything we can do about the downside of going for the top-ranked efficiency, which actually brings bottom-ranked simplicity?
1) Set up example (Catalog) Client Scripts
Client Scripts which you could simply "Insert and Stay", and modify. No need to write all the code out again.
2) Syntax Editor Macros
Write example GlideAjax call ones and save it in a Syntax Editor Macro. Syntax Editor Macros can easily be called within a Script field. Read about this in one of my previous articles: Expanding Syntax Editor Macros.
Dynamic GlideAjax
You might already notice, the functions in the Script Include can be used over and over, nice. Though for example, if you would now like to get your hands on the Email value of the User record, you would have to add a function again.
This can be done easier
I will share a Dynamic usage of GlideAjax in a future Community Article.
Platform UI, Service Portal / Client Script, Catalog Client Script
The usages of GlideAjax and the Script Include and Catalog Client Script, do work both for Platform UI and Service Portal. As example, I simply used the Incident form on the Platform UI, and therefor a Client Script. Using the exact same Script Include and GlideAjax scripting within Catalog Client Scripts should work fine.
---
And that's it actually. Hope you like it. If any questions or remarks, let me know!
Kind regards,
Mark Roethof
ServiceNow Technical Consultant @ Quint Technology
---
https://www.servicenow.com/community/developer-articles/client-side-scripting-go-for-glideajax-with-getxmlanswer/ta-p/2324830
