H
ere’s a useful script I’ve used before to grab parameters from a URL in Service-now.com. Simply pass the name of the parameter into the function and it will return the corresponding parameter value.
So if you had a Service-now.com URL that looked like this…
https://demo.service-now.com/incident.do?sys_id=-1&sysparm_query=active=true&sys_myparm=abcde
You could get the value of the ‘sys_myparm’ URL parameter by calling the function below like this…
Here’s the ‘getParmVal’ function…
var url = document.URL.parseQuery();
if(url[name]){
return decodeURI(url[name]);
}
else{
return;
}
}
I’ve often used this to automatically populate catalog variables based on a redirect URL. For example, if I were redirecting to a catalog item and I wanted to pass in a couple of variable values I could construct my URL like this…
This URL contains 3 major pieces of information…
- Pointer to the catalog item – identified by item sys_id (‘com.glideapp.servicecatalog_cat_item_view.do?sysparm_id=e826b8c50a0a3c1e019410bb1031d102’)
- A parameter containing a category value (‘&sysparm_category=hardware’)
- A parameter containing a comments value (‘&sysparm_comments=Hello World!!!’)
By passing parameters in through the catalog item URL you can use an ‘onLoad’ catalog client script (set against the item or a variable set) to pull those parameters out and populate them into your catalog item variables like this…
//Populate the variables with the parameters passed in the URL
//Use the 'getParmVal' function below to get the parameter values from the URL
var cat = getParmVal('sysparm_category');
var comments = getParmVal('sysparm_comments');
if(cat){
g_form.setValue('my_category_variable',cat);
}
if(comments){
g_form.setValue('my_comments_variable',comments);
}
}
function getParmVal(name){
var url = document.URL.parseQuery();
if(url[name]){
return decodeURI(url[name]);
}
else{
return;
}
}
When working in the Service Portal, ServiceNow severely restricts the objects available for use in client scripts, causing scripts like this to break. Brad Tilton provided this workaround on the ServiceNow community for the ‘getParameterValue’ function that is designed to work around this issue.
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regexS = "[\\?&]" + name + "=([^&#]*)";
var regex = new RegExp(regexS);
var results = regex.exec(top.location);
if (results == null) {
return "";
} else {
return unescape(results[1]);
}
}
Please note that this code snippet should be used within a client script or catalog client script on a form you’re rendering through the Service Portal. If you’re working within a widget and want to use a url parameter you would want to use angular’s $location service.
I often use RP.getParameterValue(parameter name) in conditions for UI actions as well as other places.
In many circumstances you can also either use action.getGlideURI() or gs.action.getGlideURI() as well. Here’s a snippet from one of my UI Actions:
var uri = action.getGlideURI();
var parentCollectionID = uri.get(‘sysparm_collection’);
var currentParentID = uri.get(‘sysparm_collectionID’);
Thanks for the tip. This would work in a UI action, but I’m not sure that it would apply to client scripts. Is this something that works in client scripts as well?
Mark,
I want to pass in a few variables on an order guide. However, I want the order guide to open in an IFrame within the CMS. Is this possible?
Hi Mark,
What about the left nav? When I add: ‘nav_to.do?uri=’ to the URL it no longer works??
https://instance.service-now.com/nav_to.do?uri=com.glideapp.servicecatalog_cat_item_view.do?sysparm_id=29b5a6ad0a0a0b5200d0125d6c0053c8&sys_myparm=de
I’ve never had to deal with that scenario since ‘nav_to.do’ always redirects to the URL without the frames. I wouldn’t think that it would come up much because of that.
URLs may come in like this: https://XXXXX.service-now.com/&sysparm_input=Approved
OR they may come in like this: https://XXXXX.service-now.com/nav_to.do?uri=%26sysparm_input=Approved
NOTE: If using “nav_to.do?uri=” (which loads the record inside the ServiceNow frame) as in the second example above, you must use “%26” (the URL-encoded character “&”) before the custom sysparm.
this is because the nav_to.do page/processor/thing seems to strip any sysparms from the url before passing it into the frame. Normally the processing of any sysparms would be done by scripts sitting in the frame html, at least that’s my guess.
I see how that works, and I’ve attempted to do the same with one of my service catalog items. However, I continue to get a ‘Not Authorized’ window when I try a link with a parameter in it. Here’s the URL I’m trying:
https://.service-now.com/com.glideapp.servicecatalog_cat_item_view.do?sysparm_id=ebaf65dc0a0a3c49009a3135931427c1%26account=jqpublic
I saw the ‘not authorized’ before I added the client script, so I don’t think I’m even getting to the ‘onload’ part to call it. I’m sure it’s something basic, but I can’t find a reference to it in this context. If I remove the %26account=jqpublic, then it loads the item with the fields blank, as it should.
Try just an ‘&’ symbol instead of ‘%26’.
Ack. That was it. Serves me right for not starting from scratch. Thank you very much for the script and the reply!
Hello, for some reason my script won’t pass the parameter to the url if there is a space in it. For example, I am passing first name and last name to corresponding first name and last name variables. If you enter in first name field a name like “Tom”, and last name “Brady”, works well. If you enter ” Tom” or “Tom Joesph”, it will not populate the parameter for first name. Any ideas?
//Populate the variables with the parameters passed in the URL
//Use the 'getParmVal' function below to get the parameter values from the URL
var first_name = getParmVal('sysparm_first_name');
var last_name= getParmVal('sysparm_last_name');
if(first_name){
g_form.setValue('first_name',first_name);
}
if(last_name){
g_form.setValue('last_name',last_name);
}
}
function getParmVal(name) {
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\?&]"+name+"=([^&#]*)";
var regex = new RegExp(regexS);
var results = regex.exec( window.location.href );
if(results == null){
return "";
}
else{
return unescape(results[1]);
}
}
The first step I would take would be to alert out the value of that URL parameter to see exactly what it contains. I suspect that the spaces in the name need to be escaped in some way. If it’s just spaces you might just use a javascript replace function to replace the spaces with ‘%20’. You can google for how to do that. You might also be able to encode it using something like this when you’re creating the URL.
var first_name = encodeURI(current.first_name);
Hi Mark,
I have a requirement where the customer wants to open a catalog item directly through a link in an email. The url must contain some added field values which will be used for populating data on the catalog form(on load). We have 2 scenarios here-
1. If the user has already logged in the Service now instance and then he uses the url. The form loads perfectly and the fields get autopopulated.
2. If the user has not logged in and then he uses the url. He is redirected to login page . after providing the login credential the catalog form loads but the fields are not getting autopopulated. Also, I could find that the url is getting truncated in this case.
The url contains this structure : https://instance_name/com.glideapp.servicecatalog_cat_item_view.do?sysparm_id=6737a0b88171d90071a8e2c1496753a0&asset_sysid=1cfc1ee6815a954071a8e2c1496753c2&ci_type=xyz&update_required=Yes
Please help in finding the issue.
Thanks,
Ujjwal
Hello! I think your problem lies in the formatting of your URL. Deep linking should automatically happen if you’ve got the URL set up correctly. I recommend you check out this tool from my friend John Andersen…
http://www.john-james-andersen.com/blog/service-now/deep-link-generator.html
Thanks Mark.
The url works perfectly after using the deep link.
Does this have to be a Catalog Client Script or can it be just a normal client script?
Works just as well on a standard form using a standard client script. Just replace variable names with field names.
Running into an issue with “record not found”:
When using the following link, it works fine, however, it’s a frame inside a frame:
https://test.service-now.com/nav_to.do?uri=u_incident_rtsd.do?sys_id=2c09de0d6ff96100ee0209c54b3ee469%26sysparm_category=JPOS%26sysparm_subcategory=Layaway%20(JPOS)%26sysparm_u_training_issue=true%26sysparm_termid=SAT2%26sysparm_impact=2
I get a “record not found” error when using this link:
https://test.service-now.com/u_incident_rtsd.do?sys_id=2c09de0d6ff96100ee0209c54b3ee469%26sysparm_category=JPOS%26sysparm_subcategory=Layaway%20(JPOS)%26sysparm_u_training_issue=true%26sysparm_termid=SAT2%26sysparm_impact=2
Looks like it’s the encoding of ‘%26’ in your URL. That’s a ServiceNow thing, but you should just have to replace all of those characters with a standard ‘&’ to eliminate that error.
Any suggestions on alternatives? UI Pages don’t seem to allow the “&” symbol.
Actually, I figured it out – I use ${AMP} instead of %26
Nice job! I was just about to post that, I’m glad you figured it out. This link might be helpful in the future if you haven’t seen it already.
http://wiki.servicenow.com/index.php?title=Extensions_to_Jelly_Syntax#Ampersand
Hi Mark,
Would this work with Record Producers as well?
So on a change form (with a client script) be able to parse and stuff params from URL into a record producer variable?
thanks,
-e
Yes, it should work exactly the same way on a record producer.
Hi Mark,
Thanks for all your great posts. I noticed that when I try to use this in an UI action that redirects to a service catalog item, it does not grab the sysparms. (probably because the actual url is masked/removed when the record producer loads?) Thanks again!
(
ui action – form link
client = false
update = true
)
script:
var id = current.sys_id;
var url = ‘https://[instance]/com.glideapp.servicecatalog_cat_item_view.do?sysparm_id=983e58a46f91a10023bd5965bd3ee483&u_par_req=’ + id;
action.setRedirectURL(url);
I think you need to take out the ‘https://[instance]/’ portion from your URL. A relative link should work just fine there and should maintain the link parameters. You might try logging it out in your client script to see what the URL is on your record producer.
To follow up, I alerted out the url from the getparmval function from your on load script and it returns null.
Turns out the culprit was our TinyUrl system property. Thanks for the great script!
We use this to carry the short description and a couple other values across. We’ve noticed that if the short description contains a special character (most commonly a # or &) the special character and everything after that is excluded. Is there a simple fix to this?
Check out my response to Phil in the comment thread. It talks about encoding the information, which should help.
There is an API built into the DOM which allows you to get query parameters on the client without doing any of your own regex-ing:
var x = document.URL.parseQuery()
Try this from a console in your browser of choice, it’ll return a map of key/value pairs corresponding to the query params. Then you can just lookup the param you want with the usual javascript object access:
x[‘sysparm_name’]
for instance.
Alex, thanks for the great feedback and sorry for the delay in getting back with you on this. Your solution is much cleaner so I’ve adjusted the code above to leverage it instead!
Does this method work with a GlidePaneForm? I am trying to pass parameters into the new GlidePaneForm to pre-populate fields, but alert(window.location.href) returns no parameters.
UI Action:
var dialog = new GlidePaneForm(‘new_item’, ‘incident’);
dialog.setTitle(“New Incident”);
dialog.setSysID(-1);
dialog.addParm(‘sysparm_view’, ‘Add’);
dialog.addParm(‘sysparm_tid’, ‘Test TID’);
dialog.addParm(‘sysparm_form_only’, ‘true’);
dialog.render();
Client Script (onLoad):
alert(window.location.href);
var tid = getParmVal(‘sysparm_tid’);
alert(tid); // is blank
This solution probably won’t work in that case. I’ve got another example using ‘GlideDialogForm’ with a callback function used to populate the dialog with values after the dialog loads though. Search this link for ‘callback’ to see the example.
https://servicenowguru.wpengine.com/system-ui/ui-macros/adding-referenced-records-leaving-form/
HI Mark,
This may be unrelated to this post – I landed here as I was looking for an earlier post for a solution you had proposed for being able to tell the context of a service catalog request. I want to be able to tell if a request for a catalog item is coming via an order guide or otherwise (standalone request). i believe, in that post you talk about the getGlideURI method and being able to leverage the fact that the URL for an order guide always contains certain keywords. If all this information is enough to ring a bell, could you please redirect me to where I need to be?
I’m not sure exactly what you’re looking for, but here’s all of the content I have on order guides.
https://servicenowguru.wpengine.com/tag/order-guide/
Thanks for the response Mark! There was a post which talked about how the URL had a certain keyword everytime the request is a standalone request versus one that comes via an order guide. That was we can tell context of the origin of a request
Mark,
The above seems to work when the catalog item is being called using the standard user interface (non-cms). How would this work using CMS?
Thanks!
Matthew
Should work the same way in the CMS as long as the parameters are included in the URL.
hey Mark,
Quick follow up. The only change I had to make was on this line:
var url = document.URL.parseQuery();
Since our CMS is built on iframes, we had to change this to:
var url = top.document.URL.parseQuery();
Example url:
https://myurl.com/catalog.do?sysparm_document_key=sc_cat_item,1234567890abcdefghijklmnop?&sysparm_accomplish=peter&sysparm_needed=griffin
Thanks for the great article!
If the record producer/catalog item is within an iframe and you call the top page URL with parameters, in addition to the “top.document…” change, I had to use “top..g_form.setValue()” to set form values.
This one piece is exactly what I was missing! We also use iFrames, and my getParmVal alert kept returning undefined. Thank you for posting your solution Matthew, and thanks to Mark for your awesome script.
An interesting side note:
I needed something similar to this but far more flexible. I’ve implemented this code on one of our very complex, frequently-changing offerings, and so far it looks to be working well. It iterates through the provided URL parameters and tries to match based on the key of the parsed object. Obviously everything hinges on the parameter name, but so far it looks like g_form for invalid variable names fails gracefully and moves on to the next variable.
Just an interesting variation that might be of interest if you need something a little more ‘set it and forget it’.
function onLoad() {
url = document.URL.parseQuery();
//attempt to load the rest of the items by iterating through the url object
for(var key in url) {
//discard any sysparms
if(key.toString().indexOf(“sysparm”) < 0){
var val = url[key];
g_form.setValue(key,val);
console.log("Key: "+key+" value:"+val);
}
else{
//console.log("Key Skipped: "+key);
}
}
}
Hi Mark.
Great tutorial and the code works great, i run into a few problems though, which I hope you can help me with.
I can only execute this code from the Google Chorme Dev console, and only if i choose the iFrame as the context. Is there any way to execute this, coming from another page?
It should work from anywhere, as shown in the final catalog client script. In some cases, you need to introduce a bit of a delay to the client script using ‘setTimeout’ to make sure the page is loaded before your client script attempts to run. You can google ‘javascript settimeout’ for some examples of how to use that.
Hi Mark,
Thank you for this great tutorial. I am trying to get this working on the mobile application, but the getParmVal method does not work on the native app. Do you have a workaround for this?
Thanks in advance,
Tom
Thanks Tom. Unfortunately, ServiceNow’s Service Portal and Mobile apps don’t support any of this type of custom scripting very well. I’ve posted a potential workaround at the bottom of the article. It should work in Service Portal but I’m not sure about the mobile app. Please give it a try and see.
Please excuse me as this topic is very new to me but I am trying to achieve the same results. I’m not understanding where to find the URL… any more direction you can give would be greatly appreciated!
Hi Lisa,
The URL can be found in your web browser’s address bar.
I am using:
javascript:
var answer = RP.getParameterValue(“sysparm_user”); answer;
It is passing the user but displaying the sysID – is there a way to get it to display the display name?
Hi Mark,
I am having a similar issue as Lisa.
I created a URL and trying to fetch a String Value and pass it to from Orderguide 1 to another Orderguide 2, but with below URL, the sys_id is getitng populated but i need the display value of the sysparm_personal that user populates in Orderguide 1.
I hardcoded the sys id in sysparm_personal, but need an approach to get the display value of this string variable.
https://test.service-now.com/nav_to.do?uri=%2Fcom.glideapp.servicecatalog_cat_item_guide_view.do%3Fv%3D1%26sysparm_initial%3Dtrue%26sysparm_guide%3D3b257f364facee0056384bff9310c747%26sysparm_personal%3D6066430bdb45c3406aff591e5e9619e1
Hi Lisa,
The sysparm_user parameter stores the sys_id for the current user’s User record. If you wanted to get other information from that user record you would need to write a script. Assuming you’re doing this in a client script, I’d suggest either using an asynchronous GlideAjax call to a script include (preferred method and required if you’re working in a scoped app), or using a client-side GlideRecord query with a callback function.
GlideAjax API: https://developer.servicenow.com/app.do#!/api_doc?v=jakarta&id=c_GlideAjaxAPI
Client GlideRecord: https://developer.servicenow.com/app.do#!/api_doc?v=jakarta&id=c_GlideRecordClientSideV3API
Thanks, it works perfectly in service portal.