The Now Platform® Washington DC release is live. Watch now!

Help
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Mark Roethof
Tera Patron
Tera Patron

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.

APISimplicityEfficiencyDescription
GlideRecord getReference1st5th- 1 line of code
- Poor UX (blocks browser)
- Returns entire record 
GlideRecord2nd4rd- ~ 5 lines of code
- Poor UX (blocks browser)
- Returns entire record
GlideRecord getReference
(with callback)
3rd3rd- 5-10 lines of code (with callback)
- Best UX (does not block browser)
- Returns entire record
GlideRecord
(with callback)
4th2nd- ~ 10 lines of code (with callback)
- Best UX (does not block browser)
- Returns entire record
GlideAjax5th1st- ~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: getUserPropertiesAjax
Client 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: Incident
Type: onChange
Field 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: Incident
Type: onChange
Field 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:

find_real_file.png

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!

đź‘Ť
If this post helped you in any way, I would appreciate it if you hit bookmark or mark it as helpful.

Interested in more articles, blogs, videos, and Share projects on Performance I published?
Performance


Kind regards,
Mark

---

LinkedIn

 

Comments
The SN Nerd
Mega Sage
Mega Sage

I can't believe that "Simplicity vs Efficiency" table I wrote up 4 years ago on a random thread is still making the rounds! I thought it looked familiar!

Nice article by the way 🙂

Since then I've re-written my own getReference() on Share that:

  • Returns only the field data you need
  • Returns display values
  • Doesn't block the browser

FYI, the Expanding Syntax Editor Macros link in 2) Syntax Editor Macros  is broken.

 

 

Mark Roethof
Tera Patron
Tera Patron

Hi Paul,

Fixed the link, tnx.
The table is just... it almost says it all in my opinion and after some years still valid, I would only add using getXMLAnswer to it instead of getXML. I also mentioned your name for that. Will have a look at the SmartAjax, now I'm curious 🙂

The SN Nerd
Mega Sage
Mega Sage

I wasn't even sure if I made it but it sure looked familiar!
I looked back through my posts and found it from 4 years ago - lol

No sweat!

Arnoud Kooi
ServiceNow Employee
ServiceNow Employee

Nice writeup Mark, thanks for all the content!

I'm a fan of the table API as another option for common use-cases

I made a short video with a related comparison a while back 

Chuck Tomasi
ServiceNow Employee
ServiceNow Employee

Great info Mark. Thanks!

Another resource is Episode 5 of TechNow (Client Scripting Fundamentals)

TechNow Episode List

AshishShah
Kilo Contributor

Hi Mark

Thanks for your response. I need some more help as I am not used to this scripting.

Where do I put this script in my form?

What I am doing is this:

Maintain Items -  I have variables, one is Employee and one is old_location (I need to get current location of employee in this field). Then I have one more variable - new_location, which end user can select from list.

so, where do I put your script? 

Do I put in Catalog Client Script - OnChange for Employee field?

From your response, I think I need to put this on OnChange Catalog Client script:

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

var galocation = new GlideAjax('getUserPropertiesAjax');
galocation.addParam('sysparm_name', 'get_location');
galocation.addParam('sysparm_user', newValue);
galocation.getXMLAnswer(_handleResponse);

function _handleResponse(response) {
var answer = response;
g_form.setValue('old_location', answer);
}

}

 

Where do I then put the below get_location script?

var getUserPropertiesAjax = Class.create();
getUserPropertiesAjax.prototype = Object.extendsObject(AbstractAjaxProcessor, {
get_location : function() {
gs.info(this.getParameter('sysparm_user'));
var grUser = new GlideRecord('sys_user');

if(grUser.get(this.getParameter('sysparm_user'))) {
return grUser.getValue('location');
}
},
type: 'getUserPropertiesAjax'
});

 

Regards,

Ashish Shah

 

AshishShah
Kilo Contributor

Hi

I am getting error" There is a javascript error on your browser console" when I am using your script for displaying Location of the employee selected

OnChange of employee field:

function onChange(control, oldValue, newValue, isLoading, isTemplate) {

if(isLoading) {
return;
}

if(newValue === '') {
g_form.clearValue('old_location');
}

var gaPhone = new GlideAjax('getUserPropertiesAjax');
gaPhone.addParam('sysparm_name', 'get_location');
gaPhone.addParam('sysparm_user', newValue);
gaPhone.getXMLAnswer(_handleResponse);

function _handleResponse(response) {
var answer = response;

g_form.setValue('old_location', answer);

}

}

 

in Include script:

var UserDetailsAjax = Class.create();
UserDetailsAjax.prototype = Object.extendsObject(AbstractAjaxProcessor, {
getUserDetails: function(){
var obj = {};
var gr= new GlideRecord('sys_user');
gr.get(this.getParameter('sysparm_user_id'));

obj.location=gr.getValue('location');

var json = new JSON();
var data = json.encode(obj);//JSON formatted string
return data;
},
type: 'UserDetailsAjax'
});

 

Can you let me know what I am doing wrong

 

regards,

Ashish Shah

 

Mark Roethof
Tera Patron
Tera Patron

Hi there,

Post you question as a topic on the Community, this way you will get help/answers quicker.

If I do look at your last post. First thing that I notifce in your Script Include:
sysparm_user_id

This is not what you entered in your Client Script. So at least this is a mismatch. Possibly more, though at least this.

Kind regards,
Mark
2020 ServiceNow Community MVP
2020 ServiceNow Developer MVP

---

LinkedIn
Community article list

AshishShah
Kilo Contributor

Hi Mark

What should I have used instead of sysparam_user_id?

Should I use the field on which I am using OnChange? my field name is employee

I tried with this, but still does not work

Regards,

Ashish

 

Harsh Vardhan
Mega Patron
Mega Patron

in your client script you have to use "sysparam_user_id" not  "sysparm_user"

 

gaPhone.addParam('sysparam_user_id', newValue);

 

if you are new to glide ajax, i would suggest go with official doc for better clarification.

 

 https://docs.servicenow.com/bundle/geneva-servicenow-platform/page/script/server_scripting/reference...

AshishShah
Kilo Contributor

Hi Mark

I think I am very close to getting this working

My Client script is as follows: onChange of employee field

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

var galocation = new GlideAjax('UserDetailsAjax');
galocation.addParam('sysparm_name', 'UserDetailsAjax');
galocation.addParam('sysparm_user_id', newValue);
galocation.getXML(_handleResponse);

function _handleResponse(response) {
var answer = response.responseXML.documentElement.getAttribute("answer");
alert(answer);
g_form.setValue('remarks', answer);
}
}

My Include script is as follows:

var UserDetailsAjax = Class.create();
UserDetailsAjax.prototype = Object.extendsObject(AbstractAjaxProcessor, {
UserDetailsAjax: function(){
var obj = {};
var gr= new GlideRecord('sys_user');
gr.get(this.getParameter('sysparm_user_id'));
obj.email = gr.getValue('email');
obj.location=gr.getValue('location');
var json = new JSON();
var data = json.encode(obj);//JSON formatted string
return data;
},
type: 'UserDetailsAjax'
});

 

So, when I run this, I am getting output from alert(answer) as: 

{"email":"Ashish.Shah@ipsos.com","location":"d1c6d5ba371f9200d38bd1b543990e9e"}

So, I am getting the 2 values Email and Location.

How do I get them in separate variables so that I can use SetValue to set 1 field?

I tried g_form.setValue('remarks', answer.email) -- but does not work

Kindly suggest on this part ahead

Regards,

 

Ashish Shah

Harsh Vardhan
Mega Patron
Mega Patron

try now

 

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

var galocation = new GlideAjax('UserDetailsAjax');
galocation.addParam('sysparm_name', 'UserDetailsAjax');
galocation.addParam('sysparm_user_id', newValue);
galocation.getXML(_handleResponse);

function _handleResponse(response) {
var answer = response.responseXML.documentElement.getAttribute("answer");
var ab = JSON.parse(answer);
g_form.setValue('remarks', ab.email);
}
}

AshishShah
Kilo Contributor

Thanks Harsh. This worked for me

 

Regards,

Ashish

AshishShah
Kilo Contributor

Thanks Mark for all the help.

It is working fine at my end now

regards,

Ashish

veena
Kilo Contributor

return grUser.getValue('phone');

here we have to write

'u_mobile_number' as in my incident iam not getting the desired output

and in empty box it has to display mobile number

how to write script for this...anybody please help me...

 

Hari Prakash Y2
Tera Contributor

Hi Veena,

Please post the script you tried here. So that will be easy to guide you. Thanks.

 

Regards,

Hari

Michael Aala
Tera Contributor

Hi, Mark is it also possible in OnLoad Client Script?

Mark Roethof
Tera Patron
Tera Patron

Hi there,

 

onLoad Client Script, wouldn't scratchpad be better in that case? Or do you mean Catalog Client Script?

 

Kind regards,
Mark

amol_joshi
Tera Contributor

If you are writing an 'onSubmit' client script with GlideAjax, it's ideal to use a getXMLWait() method followed by getAnswer().

sbh
Giga Guru

In many cases I do use GlideAjax with getXMLAnswer but there are also several places where I use a default value of:

 

javascript:gs.getUser().getEmail();

 

or

 

javascript:'u_building_name=' + current.variables.v_building;  // where reference is to a custom Rooms table with a column called u_building_name

 

I see I can now use auto-populate to replace the second example (yayy!). Are these examples inefficient and bad UX too?

 

And thanks very much for this post!

Version history
Last update:
‎01-09-2020 09:49 PM
Updated by: