Generic Feedback Widget, Part VII

“The secret of getting ahead is getting started. The secret of getting started is breaking your complex overwhelming tasks into small manageable tasks, and starting on the first one.”
Mark Twain

One of the things that you often see in a feedback block is some kind of numerical or star rating in addition to the textual comments. I actually added that feature in the snh-form-field feedback type, but left it out when I set up the Generic Feedback Widget. The main reason that I left it out was to adhere to my general philosophy of keeping things simple in the beginning, but another driving factor was that the live_message table that I was using for the feedback did not have a column in which we could store the rating. Still, I always had in mind that I would circle back and address that later on at some point, and now, here we are at that very some point.

While nosing around for a place to put the rating without altering any of the existing tables, I came across the Live Poll feature. This feature utilizes three tables, one for the poll definition, one for the option definitions, and another for the actual votes cast. That was a little overkill for what I was looking for, but it would work. Live Polls are linked to a specific message in the Live Feed ecosystem, which is not quite what I needed, but it was close. In my case, I would need to link a “poll” to a conversation, which I have already linked to a specific sys_id on a specific table. The poll would then serve as the rating definition, the options would then be the rating choices, and the votes cast would be the actual ratings posted with the feedback.

My plan was to alter my existing SnhFeedbackUtils Script Include to add a couple more functions, one to get the current rating values and another to post a new rating. Each would take the table name and sys_id as arguments, and the current rating functions would return the average rating and the number of votes cast in an object. There was no reference field that would link the “poll” to a conversation, so I decided to use the question column to store the table name and sys_id, since that would never actually be seen in my particular use case. The function to fetch the current values turned out like this:

currentRating: function(table, sys_id) {
	var rating = {users: 0, total: 0, average: 0};
	var pollGR = new GlideRecord('live_poll');
	if (pollGR.get('question', table + ':' + sys_id + ' Rating')) {
		var castGR = new GlideRecord('live_poll_cast');
		castGR.addQuery('poll', pollGR.getUniqueValue());
		castGR.query();
		while (castGR.next()) {
			rating.users += 1;
			rating.total += castGR.option.order;
		}
		rating.average = rating.total / rating.users;
	}
	return rating;
},

Basically, it uses the table and sys_id to find the live_poll record, and if it finds one, it uses the sys_id of that record to find all of the live_poll_cast records linked to that live_poll. I tried to do that with a GlideAggregate, but apparently you can’t do a SUM on a dot-walked property and I needed to sum up the values in the order column from the referenced live_poll_option record. So, I ended up looping through all of the records and adding them up the hard way.

Getting the current rating info was the easy part (the part that I always like tackle first!). Posting the rating was a little more involved, mainly because the first poster for any give table and sys_id has to create both the poll record and all of the option records. To keep things simple for this current iteration, I decided that all ratings would be on a 1 to 5 scale, and built everything accordingly. Eventually, I may want to make that a configurable parameter, but that’s something worthy of future version — right now, I just wanted to get to the point where I could see it all work. Here’s the current version of this function:

postRating: function(table, sys_id, rating) {
	if (rating > 0 && rating < 6) {
		var pollGR = new GlideRecord('live_poll');
		var optGR = new GlideRecord('live_poll_option');
		var castGR = new GlideRecord('live_poll_cast');
		if (!pollGR.get('question', table + ':' + sys_id + ' Rating')) {
			pollGR.initialize();
			pollGR.question = table + ':' + sys_id + ' Rating';
			pollGR.insert();
			for (var opt=1; opt<6; opt++) {
				optGR.initialize();
				optGR.poll = pollGR.getUniqueValue();
				optGR.order = opt;
				optGR.name = opt + '';
				optGR.insert();
			}
		}
		optGR.initialize();
		optGR.addQuery('poll', pollGR.getUniqueValue());
		optGR.addQuery('order', rating);
		optGR.query();
		if (optGR.next()) {
			castGR.initialize();
			castGR.poll = pollGR.getUniqueValue();
			castGR.profile = new GlideappLiveProfile().getID();
			castGR.option = optGR.getUniqueValue();
			castGR.insert();
		}
	}
},

If you don’t pass it a rating value from 1 to 5, it doesn’t do anything at all, but if you do, then it first checks to see if the poll for this table and sys_id exists, and if not, it creates it, along with the 5 option records representing the 5 possible ratings. At that point, it looks for the one option record that matches the rating passed, and then finally, it builds a live_poll_cast record to post the rating.

That pretty much takes care of all of the background work. Now I just need to modify my widget to include a rating option with the feedback and configure some kind of display at the top that shows the average rating and the number of users who have participated in the process. Looks like I will be tackling all of that next time out.