logo

NJP

How to Write Smart GlideAjax Quickly [Part 3]

Import · Mar 13, 2018 · article

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
  • 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

image

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

View original source

https://www.servicenow.com/community/developer-blog/how-to-write-smart-glideajax-quickly-part-3/ba-p/2289176