Announcing the Global SNUG Board of Directors. Learn more here

Help
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
The SN Nerd
Mega Sage
Mega Sage

How to Write Smart GlideAjax Quickly

Contents

Part 1 - The Approach

Part 2 - Reusability

Part 3 - Extending Functionality

Part 4 - Implementing GlideAjax with 1 LOC

 

Extending Functionality

In Part 2, we created a re-usable Script Include for getting a field from any given Reference field, to be called by a Client Script.

Today, we are going to extend this to handle multiple fields.

Why Stop At One - Handle for Multiple Fields

Let's first take a look at our existing function from ShackleFreeAjax

getPairValueDisplay: function(table, sysId, fieldName) {
	var gr = new GlideRecordSecure(table);

	if (gr.get(sysId)) {

		return {
			value: gr.getValue(fieldName),
			displayValue: gr.getDisplayValue(fieldName)
		}
	}

} ;

Lets extend this Function to handle multiple field names instead of just one.

In order to do this, we will need to do the following

  • Accept multiple field names as a parameter
    • Lets use an Array
  • Return field values and display for multiple fields
    • Lets store the pairs in a struct

We will add plurals to our function name to make it clear that the output is different.

getPairValuesDisplays: function(table, sysId, fieldNames) {
		var fieldsPairValues = {}; // New Structure to contain all our field values and displays
		var gr = new GlideRecordSecure(table);

		if (gr.get(sysId)) {
			//Iterate through all our field names
			for(var f in fieldNames) { 
				var fieldName = fieldNames[f];
				
				var value =  gr.getValue(fieldName);
				if (value != null) { //Value is null if user has no read access
					var fieldValueDisplay = {
						value: gr.getValue(fieldName),
						displayValue: gr.getDisplayValue(fieldName)
					};
					fieldsPairValues[fieldName] = fieldValueDisplay; //Add field data
				}
				
			}
		}
		
		return fieldsPairValues;
		
	},

We will also need to make some changes to our client data handler function.

Lets keep separations of concerns here - 

  • We will now expect a comma separated list of field names
    • This will have to be turned into an Array
  • Call a different function
	ajaxClientDataHandler: function() {

		//Get data from the form
		var tableName = this.getParameter('sysparm_tablename');
		var sysId = this.getParameter('sysparm_sysid');
		//Handle multiple field names
		var commaSeperatedFields = this.getParameter('sysparm_fieldnames'); 
		var fieldNames = commaSeperatedFields.split(",");
		//Setup data to return to form
		var answer={};
		
		//Do server side stuff
		answer = this.getPairValuesDisplays(tableName, sysId, fieldNames);

		//Encode data to send back to the form
		return new JSON().encode(answer);

	},

 

Out new Script Include, WhyStopAtOneAjax now looks like this

 

var WhyStopAtOneAjax = Class.create();

WhyStopAtOneAjax.prototype = Object.extendsObject(AbstractAjaxProcessor, {
	
	ajaxClientDataHandler: function() {

		//Get data from the form
		var tableName = this.getParameter('sysparm_tablename');
		var sysId = this.getParameter('sysparm_sysid');
		//Handle multiple field names
		var commaSeperatedFields = this.getParameter('sysparm_fieldnames'); 
		var fieldNames = commaSeperatedFields.split(",");
		//Setup data to return to form
		var answer={};
		
		//Do server side stuff
		answer = this.getPairValuesDisplays(tableName, sysId, fieldNames);

		//Encode data to send back to the form
		return new JSON().encode(answer);

	},
		
	getPairValuesDisplays: function(table, sysId, fieldNames) {
		var fieldsPairValues = {}; // New Structure to contain all our field values and displays
		var gr = new GlideRecordSecure(table);

		if (gr.get(sysId)) {
			//Iterate through all our field names
			for(var f in fieldNames) { 
				var fieldName = fieldNames[f];
				
				var value =  gr.getValue(fieldName);
				if (value != null) { //Value is null if user has no read access
					var fieldValueDisplay = {
						value: gr.getValue(fieldName),
						displayValue: gr.getDisplayValue(fieldName)
					};
					fieldsPairValues[fieldName] = fieldValueDisplay; //Add field data
				}
				
			}
		}
		
		return fieldsPairValues;
		
	},
	
	type: 'WhyStopAtOneAjax'
			
});

 

Like good programmers, we are going to test our code before even thinking about our Client Script.

This is key to not wasting hours mucking around with Client Scripts! Make sure your server code works first!

Below shows a quick little Test Harness I did to make sure the Display Values are being returned.

Use whatever tools you have at your disposal.

Let's focus on Department and Location fields, which will be our next requirement client side.

User Profile

find_real_file.png

Test Harness (Basic Example)

function positiveTestOne() {
  var table = 'sys_user';
  var sysid = gs.getUserID();
  var fields = ['department','location'];
  var ajaxTest = new WhyStopAtOneAjax();
  var answer = ajaxTest.getPairValuesDisplays(table,sysid,fields);
  if (answer.department.displayValue != "IT") {
    throw('FAIL: Department NOT IT');
  }
  if (answer.location.displayValue != "Australia") {
    throw('FAIL: Location NOT America');
  }
}  

try{
  positiveTestOne();
} catch (e) {
  gs.addErrorMessage(e);
} finally {
  gs.addInfoMessage('Test Complete');
}

 

Client Side

A new requirement has emerged - retrieving Location and Company! We have already tested our code, so we are confident that this can work with Company instead of Department.

Old code - Get Location

 

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

	if (isLoading || newValue === '') {
		return;
	}

	var ga = new GlideAjax('ShackleFreeAjax'); //Name of the Ajax Script Inclide
	ga.addParam('sysparm_name','ajaxClientDataHandler'); //Method to call
	
	//Add new parameters for our new GlideAjax Class
	ga.addParam('sysparm_tablename','sys_user'); //Table name
	ga.addParam('sysparm_sysid',newValue); //newValue
	ga.addParam('sysparm_fieldname','location'); //Field name we want to retrieve
	ga.getXML(userCallback);}

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

function setLocation(caller) { //returns only the values we need

	if (caller) {
		g_form.setValue(
			'location', 
			caller.location.value, // use value
			caller.location.displayValue //set value to avoid round-trip
		);
	}

}

New code - Get Location & Company

We need to change the code to

  • Use new Script Include
  • Pass multiple fields to server
  • Set Company field
  • Change function names to reflect code changes
function onChange(control, oldValue, newValue, isLoading, isTemplate) {

	if (isLoading || newValue === '') {
		return;
	}
	jslog('hi');
	var ga = new GlideAjax('WhyStopAtOneAjax'); //Name of the Ajax Script Inclide
	ga.addParam('sysparm_name','ajaxClientDataHandler'); //Method to call
	
	//Add new parameters for our new GlideAjax Class
	ga.addParam('sysparm_tablename','sys_user'); //Table name
	ga.addParam('sysparm_sysid',newValue); //newValue
	ga.addParam('sysparm_fieldnames','location,company'); //Field name we want to retrieve
	ga.getXML(userCallback);
}

function userCallback(response) {
	var answer = response.responseXML.documentElement.getAttribute("answer");
	answer = JSON.parse(answer);
	setLocationAndCompany(answer);
}

function setLocationAndCompany(caller) { //returns only the values we need

	if (caller) {
		g_form.setValue('location', caller.location.value, caller.location.displayValue); //set value to avoid round-trip
		g_form.setValue('company', caller.company.value, caller.company.displayValue); //set value to avoid round-trip
	}

}

 

So there you have it!

You now have a GlideAjax Script include that can handle any table and fields!

See Part 4: Implementing GlideAjax with 1 LOC

6 Comments