- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
02-08-2019 07:09 AM
Hello,
We are deploying a few service catalog items in service portals and are having issues with catalog client scripts in service portal. They work fine i platform UI, com.glideapp.servicecatalog_cat_item_view.do, but not in service portal. Below is an example of an onChange catalog client script that we are having issues with. We are asking the user if they are the main point of contact for the request. If so, the client script auto populates the the contact name, email and phone number from the current loged in user. The first name and last name are populating correctly, but the email and phone number are not. Any help here is very much appreciated! Catalog client script below.
function onChange(control, oldValue, newValue, isLoading) {
if (isLoading || newValue == '') {
return;
}
var choice = g_form.getValue('main_contact_question');
var user = new GlideRecord('sys_user');
user.get(g_user.userID);
var useremail = user.email;
var usernumber = user.phone;
if (choice == 'yes'){
var add1 = g_user.firstName;
var add2 = g_user.lastName;
var add3 = add1 + " " + add2;
g_form.setValue('contact_name', add3);
g_form.setValue('contact_email', useremail);
g_form.setValue('contact_phone_number', usernumber);
}
if (choice == 'no'){
g_form.setValue('contact_name', '');
g_form.setValue('contact_email', '');
g_form.setValue('contact_phone_number', '');
}
}
Solved! Go to Solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
02-08-2019 11:23 AM
Hi Tyler
As discussed in your previous thread, you should be using async GlideAjax to return the user details from the server.
GlideAjax has two components, client-side call and a script include on the server side. I've broken your example into the relevant components below:
onChange Client Script
Code:
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading || newValue === '') {
return;
}
var choice = g_form.getValue('main_contact_question'); //get users answer to whether they are the main contact
var fields = "name,email,phone"; //comma separated list of required field names.
if (choice == "yes"){
var ga = new GlideAjax("userUtils"); //name of script include
ga.addParam("sysparm_name","userAjaxHandler"); //name of function
ga.addParam("sysparm_usersysid",g_user.userID); //user sys_id
ga.addParam("sysparm_fields", fields); //comma separated list of required field names.
ga.getXMLAnswer(callBack); //name of call back function
}
//clear values if choice is not "yes".
else {
g_form.setValue('contact_name', '');
g_form.setValue('contact_email', '');
g_form.setValue('contact_phone_number', '');
}
function callBack(answer) {
if (answer) {
//g_form.addInfoMessage("User details: " + answer);
var user = JSON.parse(answer); //convert answer string into JSON object
/*set the required fields*/
g_form.setValue('contact_name', user.name);
g_form.setValue('contact_email', user.email);
g_form.setValue('contact_phone_number', user.phone);
}
}
}
Client Callable Script Include
Script Include Configuration:
Code:
var userUtils = Class.create();
userUtils.prototype = Object.extendsObject(global.AbstractAjaxProcessor, {
userAjaxHandler: function() {
/*extract parameters from client script call */
var userSysId = this.getParameter("sysparm_usersysid");
var fields = this.getParameter("sysparm_fields");
/*create an array from the comma separated listed you have passed*/
var fieldsArray = fields.split(",");
/*call helper function to return the user details based on the required fields*/
var answer = this.userDetails(userSysId,fieldsArray);
return JSON.stringify(answer);
},
userDetails: function(userSysId, fields) {
//gs.info(gs.getMessage("BLS userDetails: userSysId: {0} - fields: {1}",[userSysId,fields]));
var details = {}; //create object to store results
var user = new GlideRecord("sys_user"); //query sys_user table
if (user.get(userSysId)) { //since we have the users sys_id we can use "get" to return the GlideRecord
/*cycle through the fields array*/
for (var i=0; i< fields.length; i++) {
var field = fields[i]; //extract field name from array
var fieldValue = user.getValue(field); //extrat field value based on field name
//gs.info(gs.getMessage("BLS: field: {0} - field value: {1}",[field,user.getValue(field)]));
if (fieldValue) {
details[field] = fieldValue; //if the field has a value then add to object
}
else {
details[field] = ""; //if the field is empty then return blank.
}
}
}
return details;
},
type: 'userUtils'
});
I haven't been able to fully test this but it should be pretty close. Let me know if it worked for you.
Brent
P.S. If my suggestion helped then please mark as helpful and/or correct so other community members can benefit from this information.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
02-11-2019 02:13 PM
Hi David,
Yeah, glad you saw where my code was going.
We have a similar script include, that we pass the table name, to make it completely flexible. We lock this down, by using GlideRecordSecure, so only the records the user has security access to will be returned. We also return the value and display value of reference fields we wish to return, this prevents a round trip to the server as we are able to set the value and displayValue on the client side in one hit.
Example of a TableAjaxUtil below:
var BLSTableAjaxUtils = Class.create();
BLSTableAjaxUtils.prototype = Object.extendsObject(AbstractAjaxProcessor, {
/*_________________________________________________________________
* Description: Multi-purpose ajax utility to return multiple fields from any reference field
* PARM1: sysparm_tablename - tablename to query
* PARM2: sysparm_sysid - sys_id of record
* PARM3: sysparm_fieldnames - array of comma separated field names
* Returns: @String - JSON object containing value and display value of the fields listed in sysparm_fieldnames
* Client Call:
var ga = new GlideAjax('BLSTableAjaxUtils'); //name of script include to call
ga.addParam('sysparm_name', 'ajaxClientDataHandler'); //name of function within script include 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); //local function to process results
________________________________________________________________*/
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 = {};
//call function to retrieve value and display value for fields requested by the client
answer = this.getPairValuesDisplays(tableName, sysId, fieldNames);
//Encode data to send back to the form
return JSON.stringify(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 fieldValueDisplay = {};
var value = gr.getValue(fieldName);
if (value != null) { //Value is null if user has no read access
fieldValueDisplay = {
value: gr.getValue(fieldName),
display_value: gr.getDisplayValue(fieldName)
};
}
else {
/*return empty key value pair if the desired field is blank or not accessible to the user.
This is to ensure that client scripts do not fail when trying to reference a missing key value pair */
fieldValueDisplay = {
value: "",
display_value: ""
};
}
fieldsPairValues[fieldName] = fieldValueDisplay; //Add field data
}
}
return fieldsPairValues;
},
type: 'BLSTableAjaxUtils'
});
Paul Morris wrote an excellent series of Smart GlideAjax blogs which I have adopted his approach. Some of the methods used in the article have been surpassed (i.e. "new JSON().encode(answer)" should now "JSON.stringify(answer)") but his methodology is strong.
Highly recommend giving this a read.
Brent
P.S. If my suggestion helped then please mark as helpful and/or correct so other community members can benefit from this information.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
02-12-2019 12:30 AM
Yeah nice script Brent 🙂 can't really emphasize how important it is to make your script includes generic like that, saves you so much time.
I linked to that article by Paul in my original response, it really is a very good breakdown of method and best practice. Kinda wish i'd had access to it when i was first figuring out GlideAjax, rather than just fumbling my way along 😄
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
02-12-2019 01:07 AM
Yeah Paul is really switched on! Funny we both referenced him 🙂 Nice talking David. Have a good one. Brent
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-18-2020 05:04 AM
Should the code work on record producers as well as catalog items? My version doesn't seem to call the AJAX Script Includes

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
02-08-2019 11:33 AM
Just a thought on the previous replies on the GlideAjax, I think getReference, which also runs asynchronously as long as you're using a callback function, would be a simpler solution in this case to get the user's name and email address.