GlideAjax Response Null - Script Include not running?

Hurleybird
Tera Expert

Hi there, I'm a newbie that feels like I'm trying to do something beyond my skills - so I apologise in advanced if I'm missing any real basics.

Ultimate Goal: Use a Client Script to trigger a Guided Tour when a Case is in a specific state. Once the Tour has been viewed (tourCompleted) or dismissed (tourDismissed), the tour should not start.

I've used a script from Community Member athm (https://community.servicenow.com/community?id=community_article&sys_id=4d846de3db47130023f4a345ca961...) to achieve the conditional triggering. This works like a charm!

I plan to write an entry to "sys_guided_tour_user_overrides" if the user views or dismisses the tour. For now, I have manually added the entry in the table to test whether I can read from the table:

find_real_file.png

In order to read from the table, I was originally planning to utilise the Script Include "GTAutoLaunchController". However, rather than messing with a "system" Script, I created my own version of it, to allow me to make it Client Callable and mess around with it. From the Client Script, I am attempting a GlideAjax call. But no matter what I have tried, I believe that it's not triggering the script.

I have added gs.info in various places within the Script Include in an attempt to help me troubleshoot, but nothing appears in the System Log (syslog.list).

The Client Script is as follows:

function onChange(control, oldValue, newValue, isLoading, isTemplate) {
   if (isLoading || newValue === '') {
      return;
   }
	
	//If the current state of the form meets your conditions, launch the tour
if(g_form.getValue('resolution_code') != '0'){
	
	var ga = new GlideAjax('sn_tourbuilder.GTAutoLaunchUtils');
	ga.addParam('sysparm_name', 'getOverriddenToursForUser');
	ga.addParam('sysparm_userID', g_user.userID);
	ga.getXML(checkOveride);
	g_form.addInfoMessage(JSON.stringify(ga));
}
	
	function checkOveride(response) {
		g_form.addInfoMessage("Response was: " + JSON.stringify(response));
		var answer = response.responseXML.documentElement.getAttribute("tourId");
		g_form.addInfoMessage(JSON.stringify(answer));
// 		answer = answer.evalJSON();
// 		g_form.addInfoMessage(answer);
		
// 		for (var i=0 ; i < answer.length ; i++) { //Loop into the array
		
// 				g_form.addInfoMessage(answer[i].tourID);
		}
// 	}

top.NOW.guidedToursService.startTour("81996c861b515810e8a7eca13d4bcb6c", 0);
//(sys_id of the guided tour you want to launch, step#)

//Check if the guided tour is dismissed by the user, if so then end the tour. 
//If not the system will dispaly a message if the user navigates to a different form
//before the completion of the guided tour.

	setInterval(function(){
		if(top.NOW.guidedToursService.isDismissed){
			top.NOW.guidedToursService.endTour(); 

			clearInterval();
		}
		
	},2000);
}

The results from the InfoMessages are as follows:

g_form.addInfoMessage(JSON.stringify(ga));

{"contextPath":"xmlhttp.do","params":{"sysparm_processor":"sn_tourbuilder.GTAutoLaunchUtils","sysparm_scope":"sn_customerservice","sysparm_want_session_messages":true,"sysparm_name":"getOverriddenToursForUser","sysparm_userID":"a1fa60be1b6e40d044addac3cc4bcbb9"},"encodedString":"","encode":true,"processor":"sn_tourbuilder.GTAutoLaunchUtils","wantRequestObject":false,"runRequestInBatch":false,"wantAnswer":false,"async":true}
 
I've bolded what I believe are the key parameters, that seems to suggest it's passing what I believe is required to trigger the script and pass the correct variables?
 
g_form.addInfoMessage("Response was: " + JSON.stringify(response));
 
Info MessageResponse was: {}
 
g_form.addInfoMessage(JSON.stringify(answer));
Info Messagenull
 
The Script Include is as follows:
var GTAutoLaunchUtils = Class.create();
var tourTypes = {
	SERVICE_PORTAL: 'service_portal',
	PLATFORM: 'platform',
	CUSTOM: 'custom_ui'
};
GTAutoLaunchUtils.prototype = Object.extendsObject(global.AbstractAjaxProcessor, {

    type: 'GTAutoLaunchUtils'
});
GTAutoLaunchUtils.prototype.tableNames = {
	tours: 'sys_embedded_tour_guide',
	userOverrides: 'sys_guided_tour_user_overrides'
};
insertOverride = function(tourId, userId) {
	var rec = new GlideRecord(this.tableNames.userOverrides);
	rec.initialize();
	rec.tour = tourId;
	rec.user = userId;
	rec.disable_autolaunch = true;
	rec.insert();
};

removeOverrides = function(page, userId, portal) {
	var self = this;
	var pages = this.getToursForPage(page, portal);
	var ids = pages
				.map(function(d) { return d.id; })
	;
	if (ids.length) {
		var rec = new GlideRecord(self.tableNames.userOverrides);
		if (userId) {
			rec.addQuery('user', '=', userId);
		}
		rec.addQuery('tour', 'IN', ids.join(','));
		rec.deleteMultiple();
		return {ids: ids};
	} else {
		return null;
	}
};

overrideTourForUser = function(tourId) {
	var currentUser = gs.getUser();
	var rec = new GlideRecord(this.tableNames.userOverrides);
	rec.addQuery('user', '=', currentUser.getID());
	rec.addQuery('tour', '=', tourId);
	rec.query();
	var exists = rec.next();
	var tourRecord = new GlideAggregate(this.tableNames.tours);
	tourRecord.addQuery('sys_id', '=', tourId);
	tourRecord.query();
	if(tourRecord.hasNext() && !exists) {
		this._insertOverride(tourId, currentUser.getID());
		return {msg: this.messages.done};
	} else if(tourRecord.hasNext() && exists && !rec.disable_autolaunch){
		rec.disable_autolaunch = true;
		rec.update();
		return {msg: this.messages.done};
	}else {
		return null;
	}
};

overrideAllToursForUserInPage = function(page, portal) {
	var self = this;
	var currentUser = gs.getUser();
	var userId = currentUser.getID();
	var res = this._removeOverrides(page, userId, portal);
	if (res) {
		res.ids.forEach(function(id) {
			self._insertOverride(id, userId);
		});
		return {msg: self.messages.done};
	} else {
		return null;
	}
};

getOverriddenToursForUser = function() {
	gs.info("The script ran");
 	var userID = this.getParameter('sysparm_userID');
	var gr = new GlideRecord("sys_guided_tour_user_overrides");
  var data = [];
  gr.addQuery('user', userID);
  gr.addQuery('disable_autolaunch',true);
  gr.query();
	gs.info("This is killing me, will this work " + gr.tour);
  while(gr.next()) {
	gs.info("Results from this script " + gr.tour);
	var elem = {tourId: '' + gr.tour};
	data.push(elem);
  }
	return data.toString();
};

I have tried to follow all of the advice in GlideAjax Troubleshooting Guide, I've attempted multiple variations on passing arrays, JSON etc. I've tried different methods of logging, but I believe that gs.info is correct for a Scoped Application.

Ultimately, I'm not convinced that the script is being called (due to the lack of logging). I have run a couple basic Background Scripts (in Global scope) to test whether I can indeed get a result back from the table - and I can:

var gr = new GlideRecord('sys_guided_tour_user_overrides');
gr.addQuery('user','a1fa60be1b6e40d044addac3cc4bcbb9');
gr.addQuery('disable_autolaunch',true);
gr.query();
while(gr.next()){
gs.info("Tour ID: " + gr.tour);
}

Returns:

*** Script: Tour ID: 81996c861b515810e8a7eca13d4bcb6c
var gr = new GlideRecord('sys_guided_tour_user_overrides');
gr.addQuery('user','a1fa60be1b6e40d044addac3cc4bcbb9');
gr.addQuery('disable_autolaunch',true);
gr.query();
var data = [];
while(gr.next()){
var elem = {tourId: '' + gr.tour};
data.push(elem);
}
data.toString();
gs.info(JSON.stringify(data));

Returns:

*** Script: [{"tourId":"81996c861b515810e8a7eca13d4bcb6c"}]

I'm totally at a loss and hope you can help/point me in the right direction.

Thanks!
1 ACCEPTED SOLUTION

DirkRedeker
Mega Sage

Hi

I have not tested out, but I think, you closed your Prototype definition TOO early (look at my screenshot).

find_real_file.png

You need to put all the code within the curly braces, to make them belong to the Class. You put all of your functions outside, which will make them "unreachable".

 

Below, I copied the starting part of an OOB AJAX Script include. There you can see, that all functions are INSIDE.

find_real_file.png

Additionally, make sure to name your Script Include EXACTLY as you do in the code.

 

 

Let me know if that answers your question and mark my answer as correct/helpful.

Have fun & Enjoy ServiceNow

BR

Dirk

View solution in original post

14 REPLIES 14

Thanks Dirk!

The gs.info are finally firing - giving me the confidence to troubleshoot my first GlideAjax and it's response:

I'm still getting Null responses, but I assume that'll from my endless tinkering to try to pass ANY value(s) back!

Info MessageResponse was: {}
Info Messagenull

I am sure that this was the cause of my problem (Script not firing). Let me try to wrap this up, and I'll mark your answer as the Correct Answer.
 
Many thanks

Yeeh! Great.

I am happy that I was able to get you out of the corner.

Reading your article was feeling for me crying for help. And I know these situations where you get stuck "somewhere". I am sure you can now sort out the rest of the missing part.

I would be happy, if you come back here to mark as correct, if you succeeded.

Thanks & Have fun.

BR

Dirk

Hurleybird
Tera Expert

I'm getting nowhere fast with passing/parsing the results from the Script Include back to the Client Script.

I don't know if it's because I'm working in Scoped Applications at both the Server and Client end - I suspect it is simply my lack of experience with XML/JSON.

After simply trying to return the array:

getOverriddenToursForUser : function() {
	gs.info("The script ran");
	var userID = this.getParameter('sysparm_userID');
	var gr = new GlideRecord("sys_guided_tour_user_overrides");
  var data = [];
  gr.addQuery('user', userID);
  gr.addQuery('disable_autolaunch',true);
  gr.query();
  while(gr.next()) {
	var elem = {tourId: '' + gr.tour};
	data.push(elem);
  }
	return data;
},

 

I stumbled across Glideajax: Return multiple values using Json last night. So I've tried a few things.

  1. Building a simpler array, and passing that back with
    • JSON().encode() (until I read the header about this not working in scoped applications)
    • JSON.stringify(myObject)
getOverriddenToursForUser : function() {
	gs.info("The script ran");
	var userID = this.getParameter('sysparm_userID');
	var gr = new GlideRecord("sys_guided_tour_user_overrides");
  var data = [];
  gr.addQuery('user', userID);
  gr.addQuery('disable_autolaunch',true);
  gr.query();
  while(gr.next()) {
	var elem = (gr.tour);
	data.push(elem);
  }
	var json = new JSON();
	var jdata = JSON.stringify(data);//JSON formatted string
	return jdata;
},

 

Client Script:

if(g_form.getValue('resolution_code') != '0'){
	
	var ga = new GlideAjax('sn_tourbuilder.GTAutoLaunchUtils');
	ga.addParam('sysparm_name', 'getOverriddenToursForUser');
	ga.addParam('sysparm_userID', g_user.userID);
	ga.getXML(checkOveride);
}

	function checkOveride(response) {
	var answer = response.responseXML.documentElement.getAttribute("answer");
	g_form.addInfoMessage("JSON String: " + answer); //JSON String

	answer = JSON.parse(answer); //Transform the JSON string to an object
	g_form.addInfoMessage("Object again: " + answer);

		for( var i=0 ; i < answer.length ; i++) { //Loop into the array
			g_form.addInfoMessage(answer[i]);
		}
	}

And the resulting InfoMessages:

find_real_file.png 

I feel like I'm making this much harder than it needs to be. If anyone knows where I'm going wrong, or could point me in the right direction - I'd REALLY appreciate it!

replace 

var elem = (gr.tour);

to 

var elem = {gr.tour};