How To Get Parameters/Values From a URL in ServiceNow

URL Parameters

There are a variety of methods available to retrieve the value of Parameters that are being passed in from a URL in ServiceNow. For those of you who are new to this concept, ServiceNow and most all other modern websites/platforms utilize this method to get data from one page to another. As a ServiceNow admin/developer, you will most likely use this functionality to auto-populate form data or possibly as a means of determining “state” based on previous form selections. A common use case is for turning Calls or Incidents into Requests. In this scenario you could pass the Caller as the “Requested for”, and the short description, into a “Describe your need” variable on a Catch all generic catalog item.

Over the years I have found myself repeatedly using the below techniques to grab these parameters so I wanted to make sure there was a single document that everyone could use for a quick reference.

Now on to the good stuff, an example URL parameter that I’m sure you are familiar with is “sys_id”:
http://instance.service-now.com/incident.do?sys_id=2ca8f612914d4140b1782bd13ae71f72

In this case, the parameter is “sys_id” and the value we are after is “2ca8f612914d4140b1782bd13ae71f72”.

To retrieve this from a Client Script (Client side), my mentor here at Crossfuze Solutions (Mark Stanger), has written a cool little function that allows this (click to see the full article):

var myparm = getParmVal('sys_myparm');
function getParmVal(name){
var url = document.URL.parseQuery();
if(url[name]){
return decodeURI(url[name]);
}
else{
return;
}
}

Next, if you are wanting to do the same thing in a CMS/UI Page (Server Side) then you will need to do this in Jelly.

The main way to do this is to utilize the RP object’s method called “getParameterValue”:

RP.getParameterValue('paramName')
RP.getWindowProperties().get('paramName')"

Also, while we’re discussing the RP object, a few other cool methods are as follows:

  • RP.getReferringURL() – returns to URL that got you to this page.
  • RP.isMobile() – returns true if the page is in mobile mode (browsing using a Blackberry, etc.)
  • RP.getParameters() – returns all the parameters passed on the URL (to loop through)

In terms of Jelly, I have had difficulty in the past pulling parameters using the RP methods above especially in UI Macros. Here is how I worked around it just call jelly.”the_name_of_the_param”:

<g:evaluate>
   //This works on any param name including params that dont start with "sysparm" 
   var catItemId = jelly.sysparm_id;
   //Or This works if param contains "sysparm"
   var catItemId = '$[sysparm_id]';
</g:evaluate>

To get Parameters for Business Rules/UI Actions (Server side) you can use the “getEncodedQuery”, and “getGlideURI” methods as follows:

current.getEncodedQuery().indexOf('sys_id=-1') != -1  //is a new record

gs.action.getGlideURI().toString().indexOf('parameter_looking_for_here') == value_to_check

 

ServiceNow has now started getting heavy in the AngularJS space. As such I thought I would include how to get a parameter in Angular (above client side methods still work too). This is usually done using RouteParams:

$routeProvider.when('/view1/:param1/:param2', {
    templateUrl: 'partials/partial1.html',    
    controller: 'MyCtrl1'
});

Then in your controller you would inject $routeParams to use them:

.controller('MyCtrl1', ['$scope','$routeParams', function($scope, $routeParams) {
  var param1 = $routeParams.param1;
  var param1 = $routeParams.param2;
  ...
}]);

 

Fun Tidbit:

As if all of these other methods weren’t enough, there is an additional method that I recently came across in a StackOverflow post that shows a fully customizable approach (in case you were looking to do something unique with URL parsing). There are a number of example solutions on the question, but the post by Haim Evgi had one of the best looking approaches (uses a Regular Expression to parse the URL) so I thought I would convert this into a Script Include for use on the Server side:

ParamsUtil.getValueFromURL = function(param_name,full_url){
   param_name = param_name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
   var regexS = "[\\?&amp;]"+param_name+"=([^&amp;#]*)";
   var regex = new RegExp( regexS );  
   var results = regex.exec( full_url );
   if( results == null ){
      return "";
   }
   else {
      return results[1];
   }
};

Example Usage:

var params_list = ['sys_id','sysparm_query'];
for (i=0; i &lt; params_list.length; i++){
var parameter = params_list[i];
var url = 'https://dev10592.service-now.com/incident_list.do?sys_id=f6cb98490f221a001709c09ce1050ee1&amp;sysparm_query=active%3Dtrue%5Eassigned_toISEMPTY%5Ecaller_id%3D7e85d1bc0f755a401709c09ce1050e97'; 

gs.print(ParamsUtil.getValueFromURL(parameter, url));

Output:Example Output

Referenced Articles:

http://www.servicenowguru.com/scripting/client-scripts-scripting/parse-url-parameters-client-script/

http://wiki.servicenow.com/index.php?title=Extensions_to_Jelly_Syntax

http://stackoverflow.com/a/979997

 

How to Debug an Object in ServiceNow?

The following tools we will discuss today should give you some great options when it comes to debugging objects in ServiceNow.

The first option we need to discuss is the “Xplore” (version 3.5 currently) utility by James Neale. If you are not using this Developer tool then you should get this must-have utility immediately. If you ever wondered what was in a GlideRecord (or most any other object), or wished the “Background Scripts” tool had a better interface then this should be your go-to utility. There are a number of additional capabilities that this tool offers but this is my favorite.

Of course there are other ways to pull info on objects, but the interface on this utility is extremely intuitive and makes dissecting objects on the server side very easy. You can find this utility on ServiceNow’s Share site, or on GitHub.

Xplore (big)

One other tip that I discovered is that once’s its installed its possible to utilize its “xplore” function to parse objects to the log as well (handy when trying to debug objects on the fly and dump to the system logs):

var xplore = new snd_xplore(object);
gs.print(xplore);

xplore Command

Note that the “xplore” function name is subject to change as they release newer versions.

So now that we’ve covered Xplore, on to other tools that should be in your toolbox for object exploration. These are needed if you are not going to use the Xplore utililty and need to troubleshoot realtime communication and logging the output from within your own scripts. Here are the other one’s I’ve used:

Other Server Side Tools
There is a cool Script Include that is included OOB in ServiceNow called “JSUtil”. If you haven’t used/seen it previously, take the time to check it out; there are some great functions including one called describeObject that can be used to parse basic objects:

JSUtil.describeObject(object)

describeObject

Note that the JSUtil is not available/callable from within scoped applications.

Another option is to try outputting your (JSON compliant) object using the built-in JSON Script Include. This tool is great for “stringifying” data to make it readable on the server side:

gs.log(global.JSON().encode(object))

 

Ok, so you’re covered on the Server side of things, but what about the Client? 

Below are some Client Side Tools that allow you to debug objects in on the client/browser:

JSON().stringify(object)

If you are not using objects as properties in your object you may be able to use the JSON methods: JSON.stringify() on the client side, or JSON.encode() on the Server side. But again, that won’t work if the object uses functions or other properties which aren’t serializable to JSON.

One final Method is to use a simple loop; note that this ignores the Prototype inherited properties by using the “hasOwnProperty” check:

for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var val = obj[key]; // use val }}

A final tool you can use if you are in a browser like Chrome is DevTools. You can easily utilize “console.log(objectName)” in the Console (to open this just right click on a blank area of the page and choose “inspect) browser to then click through an object. Below is a screenshot showing how this can be done, I have used the “g_form” object as an example, and then started clicking through its keys/properties:

Debugging an Object - g_form

One thing to note, if you are doing this within the “Full Frame set” (includes the navigation bar), then you will need to select the “gsft_main(tableName.do), frame before you can start debugging. Alternatively just open your form in a new window that doesn’t have the navigation/top panel (control click on the link):

Console Debug iFrame

If you are not using Chrome (I’m sorry :)), you can always use something like the Firefox (Firebug) to do the same thing.

Have I missed any other common tools/methods? Please let me know!

Workflow Driven Catalog UI Policies

Recently I was working with a client on a large Service Catalog project. One of the requirements was that they needed to have specific variables to be visible/required on catalog tasks based on where the item was within the workflow and based on answers that were given to other variables. There are obviously many ways to tackle this; at a very basic level you can choose to show/not show these variables via the slushbucket on the task activity. While this does work in most cases, in more complex scenarios like this, it does not cover the capability to conditionally show/hide certain variables based on the values of other variables. In the past, I have tackled these types of issues by using UI Policies that looked for specific text/data in order to “figure out” where the item was at in the workflow. While this approach can work in certain circumstances, I wanted a more robust method of controlling what fields were required/visible/mandatory. The result was “Workflow generated UI Policies” that can be called by any item (using a Catalog Client Script), with a back-end AJAX Script Include that queries the item’s Workflow context, then grabs the UI Policies (exist as a scratchpad array) off of the scratchpad, figures out which one is applicable, then sends the payload back to the client script.

Here is what the Workflow Run script contains:

//set UI Policy scratchpad
workflow.scratchpad.ui_policies = [];
workflow.scratchpad.ui_policies.push(
		{
			"applies_to": workflow.scratchpad.task_sys_id,
			"readOnly": ['group'],
			"writeable":['first_name','last_name','laptop'],
			"mandatory":['laptop'],
			"visible":[''],
			"hidden":['assigned_to']
		});

Here’s the Script Include:

var CatalogItemAJAXUtil = Class.create();
CatalogItemAJAXUtil.prototype = Object.extendsObject(AbstractAjaxProcessor, {

	getWorkflowScratchpad : function (){
		var req_item =  this.getParameter('sysparm_req_item');
		var record_id = this.getParameter('sysparm_record_id');
		var req_item_policies;
		var matched_policies = '0';

		//get the workflow script include helper
		var workflow = new Workflow();

		//get the requested items workflow context
		var item = new GlideRecord('sc_req_item');
		item.get(req_item);
		var context = workflow.getContexts(item);

		//make sure we have a valid context
		if (context.next()) {
			gs.log('++CatalogItemAJAXUtil: Got Policies:' + new JSON().encode(context.scratchpad.ui_policies));
			//this has already been instantiated as an array/collection, we can use it directly
			req_item_policies = context.scratchpad.ui_policies;

			//loop through all policies, find out which one's apply to this record
			matched_policies = this.getMatchingPolicies (req_item_policies,record_id);
			//gs.log('++Policy Applies to: ' + req_item_policies.applies_to +' Record we were on: ' + record_id);

		} else {
			//no workflows found for this item; ignoring...
		}
		if (matched_policies) {
			gs.log('++Returning UI Policies: ' + matched_policies + ' for Record: ' + record_id);
		} else {
			gs.log('++No Matching UI Policies found for Record: ' + record_id);
		}

		//convert to JSON String before sending
		return new JSON().encode(matched_policies);
	},

	getMatchingPolicies : function (policies,record_id){
		var item_policies = [];
		for (var i = 0; i < policies.length; i++) {
			var policy = policies[i];
			if (policy.applies_to == record_id) {
				//gs.log('++ Found matching UI Policy for this record');
				item_policies.push(policy);
			}
		}
		return item_policies;
	},

	type: 'CatalogItemAJAXUtil'
});

Finally, here is what the Catalog Client Script looks like:

function onLoad() {
	var ga = new GlideAjax('CatalogItemAJAXUtil');
	ga.addParam('sysparm_name','getWorkflowScratchpad');
	ga.addParam('sysparm_req_item',g_form.getValue('request_item'));
	ga.addParam('sysparm_record_id',g_form.getUniqueValue());
	ga.getXML(ScratchpadParse);

}

function ScratchpadParse(response) {
	var answer = response.responseXML.documentElement.getAttribute("answer");
	jslog('++ AJAX Answer was: ' + JSON.stringify(answer));
	var workflow_ui_policies = JSON.parse(answer);
	jslog('++ Scratchpad UI Policy Obj was: ' + JSON.stringify(workflow_ui_policies));

	//loop through and apply each UI Policy

	for (var i = 0; i < workflow_ui_policies.length; i++) {
		var policy = workflow_ui_policies[i];
		if (policy == '0' || policy == null){
			jslog('++ Returned UI Policy is not Valid for this record');
			continue;
		}

		jslog('++ Running Scratchpad Policies ' + policy['readOnly'] + ' String: ' + JSON.stringify(policy));
		setPolicyValues(policy['readOnly'],'readOnly');

		//jslog('++ReadOnly:' + policy['readOnly']);
		setPolicyValues(policy['writeable'],'writeable');
		//jslog('++writeable:' + policy['writeable']);

		setPolicyValues(policy['mandatory'],'mandatory');
		//jslog('++mandatory:' + policy['mandatory']);

		setPolicyValues(policy['visible'],'visible');
		//jslog('++visible:' + policy['visible']);

		setPolicyValues(policy['hidden'],'hidden');
		//jslog('++hidden:' + policy['hidden'])
	}
}

function setPolicyValues(policy_fields,action){
	for (var i = 0; i < policy_fields.length; i++) {
		var field = policy_fields[i];

		if (action == 'readOnly') {
			g_form.setReadOnly(field, true);
		} else if (action == 'writeable') {
			g_form.setReadOnly(field, false);
		} else if (action == 'mandatory') {
			g_form.setMandatory(field, true);
		} else if (action == 'visible') {
			g_form.setVisible(field, true);
		} else if (action == 'hidden') {
			g_form.setVisible(field, false);
		}
	}
}

It is these 3 pieces of code that make up the Custom Workflow UI Policy process. Once this is setup, you can have multiple custom/scratchpad UI Policies in your workflow and then based on the Record’s ID (sys_id), it will dynamically apply the corresponding UI Policy for that record.

Ok, that’s it for now, please let me know if you have any questions.