Skip navigation

Developer Community

13 Posts authored by: Brad Tilton Employee

One of the things I came across when prepping for my Jakarta blog post was that we've released a new field type called Name-Value Pairs. Intrigued by the name I looked into it and found this description from the field types article on the docs site:

 

Field that maps text values. Each mapping is one-to-one, however a single Name-Value Pairs field can contain multiple mappings. Each mapping must use a unique name, and the name cannot be empty.

 

From here I fired up a dev instance and created a scoped app (that's just how I roll), created a new table called Data, and added a name-value pair field called Data values. This is what the default record looks like:

 

Screen Shot 2017-09-19 at 9.48.18 AM.png

Adding values is very straightforward.

 

Screen Shot 2017-09-19 at 10.06.39 AM.png

 

It's nice to be able to store data like this, but I think the real value comes in when you start working with it from a script. For example, here is a script I can run against the record created above.

 

//grab the gliderecord object for the record in the screenshot
var gr = new GlideRecord('x_85636_name_value_data');
if (gr.get('a49e63a56f110300d8c252b10b3ee41e')) {

    //iterate over the current properties in the data values field and print the values
    for (var name in gr.data_values) {
        gs.info(name + " = " + gr.data_values[name]);
    }

    //add another property to the data values field
    gs.info("Adding a height property")
    gr.data_values.height = '50';
    gr.update();

    //iterate over the current properties in the data values field and print the values
    for (var name in gr.data_values) {
        gs.info(name + " = " + gr.data_values[name]);
    }

}

 

Here are the printed values:

x_85636_name_value: color = Blue

x_85636_name_value: length = 27

x_85636_name_value: width = 10

x_85636_name_value: Adding a height property

x_85636_name_value: color = Blue

x_85636_name_value: length = 27

x_85636_name_value: width = 10

x_85636_name_value: height = 50

 

And this is what the record looks like after I've added the height property to the field from the script:

Screen Shot 2017-09-19 at 10.10.58 AM.png

 

The docs article points out that this field type would be useful for holding header information for a web service request where the name of each mapping is the header such as Content-Type and the value is the header value, such as Application/json. I would expect that there are a lot of other good use cases out there for this type of field, where you need to store some data that is less structured and you don't want to create a field for every possible option.

 

If you can think of a use case where this field type could help, please share it in the comments below.

There's a pretty common use case in ServiceNow that goes something like this: A new user is onboarded and some sort of automation kicks off an onboarding process in ServiceNow. As part of the process ServiceNow sends an email to the hiring manager with a url that points to an order guide or catalog item. In that URL you might have included some url parameters that will populate some of the variables to help the hiring manager out and also to reduce the possibility or errors. In order to accomplish this you would use an onLoad catalog client script on the order guide or catalog item you're loading. The script commonly looks something like this:

 

function onLoad() {
    //Use the 'getParameterValue' function below to get the parameter values from the URL  
    var user = getParameterValue('sysparm_user');
    if (user) {
        g_form.setValue('user_variable', user);
    }
}

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

 

This works really well and is documented in a few places including one of my blog posts. However, this script will not work when your order guide or catalog item is rendered within Service Portal. The reason is that Service Portal blocks a number of javascript global objects from running within client scripts including document and prototype which are both used in line 11.

 

So what do you do if you want to use url parameters to populate values into catalog artifacts in the Service Portal? I recently discovered that the top object is not blocked, so I tried modifying this script a bit and it seems to work. I will admit that this method is more of a workaround/hack, but it's the only way I've been able to populate a variable from the url through the Service Portal so far.

 

function onLoad() {
    //Use the 'getParameterValue' function below to get the parameter values from the URL  
    var user = getParameterValue('sysparm_user');
    if (user) {
        g_form.setValue('user_variable', user);
    }
}

function getParameterValue(name) {
    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]);
    }
}

 

So in this case if your url included &sysparm_user=Brad at the end then the value 'Brad' would be populated into the user_variable variable. Something to note is 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.

 

Feel free to leave any feedback, and if anyone has a better way to do this please let us know in the comments.

Note: This blog post reflects my own personal views and do not necessarily reflect the views of my employer, Accenture.

 

There are a lot of things that are great about Service Portal, but the way widgets are implemented is one of my favorites. In this blog post I want to call out Widget Options, which help to make widgets more dynamic and reusable, and talk about some ways that you can use them.

 

For an example, if we look at the default Service Portal homepage we'll see 4 columns across the middle for Order Something, Knowledge Base, Get Help, and Community.

187b73b3e5.png

 

What is not immediately obvious is that those are 4 different instances of the same widget, Icon Link. If you go in and ctrl+right click on the order something widget instance and choose Instance Options you'll get a modal with 8 different widget options you can configure.

c572dac384.png

 

This allows us to reuse the same widget multiple times without having to rewrite code, and allows someone to customize these widgets without writing any code. Lets take a look at how the widget is written and see how these options are referenced.

07dfeff977.png

 

You can see that there are many places in the html where the options values are referenced and used in order to render the widget instance. You're not limited to the HTML field either as you can reference the options from the Server and Client script fields as well. Here are a couple of links that give some more details on how that works:

 

documentation/widget_options.md at master · service-portal/documentation · GitHub

Widget options

 

Good practice: In addition to making it easier to use the service portal without writing code, one of the things I always think about when I'm writing widgets is how I might be able to use the widget options to have to duplicate less code and write fewer widgets. For example, if you wanted to add multiple lists of records to a portal page that was structured similarly for all of them, you could pass the table you're querying, an encoded query, and the field values you want to display through the widget options.

 

I'd really like to hear of some creative ways others have used the widget options in the comments on this post.

Note: This blog post reflects my own personal views and do not necessarily reflect the views of my employer, Accenture.

 

Every now and then I'll come across a question in the community or have a customer that needs to track whether or not an item was generated from an order guide or a standard catalog item request. Sometimes they also may need to know which order guide it came from.

 

There are really a couple of ways to track that. One would involve a variable set and some cascading variables, and the other is this SNCGuru solution. They both have drawbacks, but I usually lean towards the latter partially because I try to create as few variables as possible. It's not perfect as there's a use case where it doesn't end up capturing the order guide.

 

Today I posted that SNCGuru article as a response to someone else's question and got a new response. shouvik made my day by linking to this article, and telling us that there is a feature in Helsinki that automatically captures the order guide and writes it to a field called Order guide on the requested item without the customer having to configure anything. I went ahead and tested in my Helsinki instance and, sure enough, the order guide field was populated with the order guide I used to order the items.

 

ritms.PNG

 

I figured I'd try to give it a bit more visibility as I've been working primarily in Helsinki for a while now and I try to stay on top of the newest releases and had no idea that this new functionality existed.

 

Request an order guide

Note: This blog post reflects my own personal views and do not necessarily reflect the views of my employer, Accenture.

 

One of the nice features of Service Portal is the sheer number of widgets that are included by default after activating the plugins. In today's AISP (yep, I acronymed it) post I'm going to explore one of those widgets a bit. The Form Widget.

 

One of the most common questions I used to see around CMS was something like: "How do I open this record in CMS?" There were a couple of different ways to do it with content types and detail records, a static iframe, or with a little bit of work a more dynamic iframe that would take in url parameters and render some content. Each of these methods had some drawbacks and I was never quite satisfied with both the learning curve and the result. Oh, and they all used iframes.

 

With the form widget it's easy to display any record in ServiceNow within your Service Portal without doing any configuration, all you need to do is link to it. Lets take a look at the self-service view of an incident form in the standard view of ServiceNow:

 

incidentdefault.PNG

 

We know that this form has a url that looks something like:

https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=b28a474f4fb8220067d9b5e18110c758&sysparm_view=ess

 

Without doing anything other than making sure that the Service Portal plugins are enabled, I can show this same record in my Service Portal using this url:

https://instance.service-now.com/sp?id=form&table=incident&sys_id=b28a474f4fb8220067d9b5e18110c758&view=ess

 

incidentformwidget.PNG

 

The form widget is on a page already by default that can be called in any service portal called form. You're then able to pass the page the following url parameters:

  • table - the name of the ServiceNow table where the record is located
  • sys_id - the unique identifier of the record
  • view - an optional parameter where you can specify which view the fields are pulled from
  • query - allows you to specify a query

 

If you want to include this widget on another page, you also have some widget options you can set:

  • Disable UI Actions on Form
  • Display current form view
  • Omit header options icon

 

You may have noticed that by default the form widget includes ui actions, all fields and related lists on the form view, and also client scripts and ui policies. However, there are some exceptions to those. They are documented here, but I'll list them out:

  • Client side ui actions
  • Anything that uses jelly, including
    • UI Macros
    • UI Pages/Formatters
  • Client Scripts where Run scripts in ui type is Desktop

 

In addition to those, there are a number of different client side scripting techniques and methods that are not supported. All of the Service Portal supported objects and methods are listed in the github doc below, and these are not limited to the form widget.

documentation/client_scripting.md at master · service-portal/documentation · GitHub

 

Previous blogs in this series:

Adventures in Service Portaling: Introduction and Resources

Adventures in Service Portaling: How Do I Get To That?

Note: This blog post reflects my own personal views and do not necessarily reflect the views of my employer, Accenture.

 

One of the things that I learned early on in working with Service Portal is that while there are relatively few types of artifacts to track, namely portals, pages, widgets, and widget instances there are multiple ways to view most of them. It was a bit confusing for me to be able to get to the right view of the page or widget I wanted at different times, sometimes taking me a few clicks, even when using the sp_config portal.

 

At some point I saw something that changed how I worked with Service Portal pages and widgets: CTRL+Right-Click. If you have the admin role and are looking at a rendered service portal page you can CTRL+Right-Click on any widget (think content rather than blank space) and get a menu with some great options in it.

 

EditorContextMenu.png

 

Let's walk through those here and I'll provide links to the documentation on the ServiceNow docs site and/or service portal documentation on github where applicable.

 

  • Widget Performance - The very first message tells you how long it took for the widget to load, which is a nice little feature.
  • Instance Options - You can specify options when someone adds a widget to their page which can determine how the widget is rendered. Choosing this option gives you an overlay where you can edit the values of the options for this widget instance.
  • Instance in Page Editor - This shows you the widget instance in the page editor view, with the hierarchy of all the containers, rows, columns, and widgets on the page. Clicking on a widget allows you to edit the the widget instance fields.

 

  • Page in Designer - Designer lets you add containers, columns, and widgets to a page as well as setting some styling for those artifacts.
  • Edit Container Background - This one allows you to change some of the styling of the container where the widget you clicked is located.
  • Widget Options Schema - I mentioned a bit earlier that you can edit the values for the the options of the specific widget instance you're clicking on, but this let's you edit the options definitions for the widget. If you wanted to collect an additional data point and use it in the widget definition you would do that here.
  • Widget in Form Modal - This opens the widget form in a modal overlay. You can edit field such as demo data, etc. The widget form itself isn't all that useful and there is a better alternative.
  • Widget in Editor - This is where I have spent most of my time since I've been working in Service Portal and it's an incredibly useful tool for writing and editing widgets.
  • Log to Console: $scope.data - This is one of my favorites. In Service Portal, the $scope.data object is what is used to pass data from the server to the client side controller. If you're having issues with some data coming through, instead of adding console.log messages or even alerts into your controller code, you can just log the $scope.data object to your browsers console and take a look at the data there. You could always add this to every widget and turn it on and off, but it's just a whole lot easier to render a SP page, realize that you didn't return some data you thought you would, then look at the logs without ever leaving the page.
    *Could not find any documentation on this
  • Log to Console: $scope.data - This is much like the previous, except it logs every thing in $scope to the console, so you'll get a lot more noise here, but it can be useful if you're looking for something other than data.
    *Could not find any documentation on this

 

I hope this was a useful explanation of some other feature within the CTRL+Right-Click functionality in Service Portal. I plan on going into a bit more detail on some of these topics in future blogs.

After doing some work in the new Helsinki Service Portal over the last couple of weeks I've found some things I think will be helpful for those who will be starting their Service Portal journeys. Some topics will be fairly short tips and tricks and some will be a little longer, but I think everything could be useful to someone looking to implement Service Portal.

 

Also, I know portaling isn't a real word, but apparently portaled (having a portal according to Merriam-Webster) is, so I'm going to take the liberty of using it.

 

I'm going to start this series off by listing some places where you can find official and unofficial documentation.

 

ServiceNow Official Documentation *Updated with more content

serviceportal.io Blog

CodeCreative.io Blog

ServiceNow Elite Blog

Brad Tilton's Community Blog (I'm not above a little self-promotion)

TechNow Ep. 28 - Service Portal

TechNow Ep. 29 - Service Portal Part 2

HelsinkiHint - My First ServicePortal Widget — CAVUCode

Yansa Design System

Portal Guru Blog Archives - Cerna Solutions

 

**NEW**

Developer Site - Service Portal Course

serviceportal.io github Documentation

serviceportal.io Widget Library

Live Coding Happy Hour - Service Portal Videos (scroll down for the Service Portal section)

 

Know of any other good resources? Let me know and I'll list them!

Note: This blog post reflects my own personal views and do not necessarily reflect the views of my employer, Accenture.

 

With the Helsinki release came the highly anticipated release of Service Portal. Service Portal is most widely known as being billed as the successor to CMS, but encompasses much more. ServiceNow defines Service Portal as a visual layer application that is used to render ServiceNow in a visually appealing, approachable way for non-Admin users.

 

We'll come back to that definition, but let's talk about Service Portal first as a successor to CMS. The bad news is that there is no migration path from CMS to Service Portal as they are built on different technologies. The good news is that if you have a current CMS portal built using the Bootstrap framework you can use most of that design work and styling to give you a head start on building a Service Portal.

 

One of the biggest differences between CMS and Service Portal is the underlying technology that allows you to retrieve data from the ServiceNow DB and display it on the page. CMS used Jelly which was not a very widely used framework, and thus hard to find any resources on the web as well as developers with Jelly experience. Service Portal, on the other hand, uses AngularJS to take data retrieved from the server and show it dynamically on the page. AngularJS is a very widely used JavaScript framework resulting in many resources, plugins, and experienced developers. Given this choice it should be a lot easier to ramp up a web developer with little ServiceNow experience on Service Portal compared to CMS.

 

One of the other big differences between the two is that CMS relied heavily on using iframes to display ServiceNow content along with a themed header and possibly a footer. This allowed us to show ServiceNow content fairly easily, but iframes are notoriously difficult to work with and we had little control over what was shown inside the iframe. For example, if you want the catalog content to look more like one of your other internal tools, you didn't really have a lot of options. Service Portal on the other hand is a complete visual layer between the ServiceNow content and the user, so THERE ARE NO IFRAMES, and you have total control over the formatting of the content that is displayed on the page.

 

The one downside there is that if you have a large catalog with complex catalog items, it may take more work to make those work correctly with Service Portal since it will have to interpret all of those complexities through the visual layer. With CMS we didn't have to worry about how it would be interpreted as it was just being shown in an iframe.

 

There are a few other major advantages to Service Portal.

 

  • Firstly, it was designed with a mobile first mentality, so it is truly responsive. It was technically possible to make CMS completely responsive, but it took a lot of custom development in order to make catalog items responsive.
  • Another major advantage is that Service Portal is a self-contained app on top of ServiceNow, so it will not be as susceptible to upgrade issues as CMS was. CMS typically had default ServiceNow styling applied to it, so as the styling changed throughout releases the CMS site would need its styling changed to accommodate. Service Portal has its own styling and isn't showing any content in iframes, so it's really only reliant on the underlying data structure being consistent.

 

Overall, if you're starting a new portal build and don't have a large and complex catalog you'll want to use Service Portal. If you have an existing CMS site and/or large existing service catalog you'll need to consider those things before making the decision.

 

I'll be following this post with some specifics around Service Portal. If you enjoyed this post feel free to like, share, or bookmark it!

Did you know that in Helsinki you can force a list collector variable to display as a glide list field by adding an attribute to the variable definition record? Neither did I until this morning and I wanted to share that out.

 

Why would you even want to do this? Well, list collectors are nice and basically allow you a multiple select reference field where you have all the records on a table on the left and you can move one or more values to the right.

 

9bbb8924ee.png

 

It's a nice feature, but list collector variables take up a ton of space, load more slowly than other variable types, and require some DOM manipulation in order to set the values on the right hand side. It's a pretty common ask to use the list field type (like the watch list on the task table) as it takes up less room, loads more quickly, and can be manipulated using the g_form.setValue() method. It's been possible to do this in the past, but requires a ui macro and hasn't worked all that well for me.

 

In Helsinki, I can add the glide_list attribute to the variable definition and then that list collector magically turns into a glide list.

4fc2c09e20.png

Shows this:

9fdbbb2ea7.png

Expanded:

9d89822602.png

 

I think there is definitely a place for both of these types of renderings, but it's nice to have an easy way to toggle between the two.

 

Types of variables

A while back I was working on a project where I ended up having to write some GlideRecord queries based on quite a few different tables and parameters. I was using syntax editor macros along with the find and replace feature in the syntax editor, but it seemed to me like it should be easier than.

 

I started thinking about what I really wanted, and what I decided was that I wanted a way to generate a GlideRecord query from a list that contained the table name, the encoded query string, the sort field, and allow me to set the variable name of the GlideRecord object. Once I had those goals, the execution was actually pretty straightforward, so I built it out and uploaded it to share.

Get GlideRecord Query from List

 

Here's a screenshot demo of how it works after you've uploaded the update set into your instance.

 

First you can go to any list and add some queries to the filter:

f7ec25aab5.png

 

Then run the query and click the Get Query list banner ui action and you'll get a prompt to name you GlideRecord object variable.

6275146d65.png

 

Name it (something other than gr) and hit ok, and you'll get another popup with your generated GlideRecord code.

6df0851be5.png

 

Now hit CTRL+C and paste that into your script editor of choice:

db469d27c5.png

 

That's it! Just a simple way to easily generate a GlideRecord query from a list of records to use wherever you'd like.

Last year at the inaugural CreatorCon I had the opportunity to write and present a session called Building a Killer UX when students built out a front end for a custom, scoped ToDo application using Bootstrap and AngularJS. I had a lot of fun and learned a ton both writing and presenting the session, and it was pretty well received.

 

This year, my colleague Mitch Stutler and I are happy to present a couple of sessions around using AngularJS in ServiceNow.

 

From Jelly to Angular - Mitch Stutler

In this session you'll take a PPM dashboard built in Jelly and go step by step to rebuild it using AngularJS. You'll learn things like going from <j:while> in Jelly to ngRepeat in AngularJS. This will be ideal for a ServiceNow developer who is familiar with jelly and wants to learn more about AngularJS, someone who will be converting a CMS site to use something AngularJS based like Service Portal, or someone who just wants to learn more about building dashboards in AngularJS in ServiceNow.

 

Building a Killer UX - Brad Tilton

This session will be similar to last year's session, but updated a bit. In this session you'll build out a UI Page in Bootstrap and AngularJS that will act as a front end for an updated ToDo app as well as build a Scripted REST API in addition to using ServiceNow's REST Table API.

 

Dates/Times

19CB04 - From Jelly to AngularJS (repeat 1 of 2) - Thursday, May 19, 1:30 PM - 3:20 PM

20CA06 - From Jelly to AngularJS (repeat 2 of 2) - Friday, May 20, 8:00 AM - 9:50 AM

20CC04 - Building a KillerUX v2 - Friday, May 20, 10:30 AM - 12:20 PM

 

I'm really excited to be presenting this year and looking forward to being at CreatorCon in two weeks!

One of the most common questions that I see on the ServiceNow community is some variation of “How do I populate values on my form via the URL?” There are many circumstances where you already have values for some fields/variables and you’re sending a form to someone to fill out whether redirecting there or through email. In those cases you don’t want to make your user go find that information or even have to enter it into the form if it’s already available. There are three main areas in ServiceNow where this is most commonly done:

  1. A table form (Incident, Facilities, etc.)
  2. A Catalog Item, Record Producer, or Order Guide
  3. A UI Page/CMS Page

The documentation is all out there already, but I thought I’d pull it all together in one place.

 

Table Form

One of my favorite wiki articles is called Navigating by URL and does a really good job explaining how to build a url that will prepopulate values on a form. The basic anatomy of the url is:

https://<instance name>.service-now.com/nav_to.do?uri=incident.do?sys_id=-1%26sysparm_query=caller_id2809952237b1300054b6a3549dbe5dd4

incident – this is the name of the table you’re redirecting to
sys_id=-1 – passing negative one as the sys_id tells ServiceNow you’re opening a new record
sysparm_query – this is the parameter where you will set your values
caller_id2809952237b1300054b6a3549dbe5dd4 – this is the encoded query you will use to set the caller to a specific indivdual

 

Catalog

Setting a value via URL requires a little more work in a catalog item/record producer, but luckily there’s a really great SNCGuru article called Parse URL Parameters in a Client Script that I’ve use many, many times to accomplish this.

For this method, you add some sort of parameter to the end of the url of the catalog item. In this case, you can pass the sys_id of a user with the sysparm_user parameter:
https://<instance name>.service-now.com/nav_to.do?uri=com.glideapp.servicecatalog_cat_item_view.do?sysparm_id=d65394f54ff2520020af09fd0210c759&sysparm_user=2809952237b1300054b6a3549dbe5dd4

 

Now that you’ve passed it you have to use an onload client script on the catalog item itself to consume that parameter and most likely set a value with it like this:

 

function onLoad() {
    //Use the 'getParameterValue' function below to get the parameter values from the URL
    var user = getParameterValue('sysparm_user');
    if (user) {
 g_form.setValue('user_variable', user);
    }
}

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

 

NOTE: This script looks a little different if you want to use it through the Service Portal as document and prototype will not work there. Check out the updated script here.

UI Page

The third place you might want to pass a url parameter would be a ui page. UI Pages in ServiceNow are custom pages built using jelly. The wiki article in this case isn’t quite as informative, and it’s called Extensions to Jelly Syntax. In this scenario, if you wanted to pass a user sys_id to the jelly in the page, you could do:

https://<instance name>.service-now.com/fancy_user_page.do?sysparm_user=2809952237b1300054b6a3549dbe5dd4

 

Then in jelly you can do something like:

<j:set var="jvar_user_sysid" value="${RP.getParameterValue('sysparm_user')}">

 

Then you can use that jelly variable later on in your UI Page.

 

Hope this post was helpful, and I'll be following up later with how to pass a url parameter into an angular based UI Page.

I stumbled across a new Fuji feature a while back around script includes and ajax calls that I thought was pretty handy. I haven’t seen much about it on the community so I figured I’d call it out here.


If you’ve ever used GlideAjax in ServiceNow to run some server side code from a client script you know that there are two parts to the process. You need to initialize GlideAjax from the client side, most likely from a client script, and then you also need a script include on the server side where you’ll run your server side code.


If you’re like me you probably start by copying the client side code from the wiki article and changing the parameter names, and then you do the same with the server side code and change the function names. In Fuji this has gotten a little easier.


If you’re creating a standard script include to be used server side, the functionality has been around a while where ServiceNow will fill in some starter code after you name your script include.


6acffb2afd.png


The problem with doing this for a script include that needs to be called from the client is that you need to extend the AbstractAjaxProcessor object and you don’t want to override the initialize function. Well, in Fuji at this point you can check the Client callable checkbox and voila!


ed7b32596d.png


The nice thing about this is you don’t have to do anything differently than you normally would, and it saves you the time of copying and pasting from the wiki article.


If you find this article helps you, don't forget to log in and "like" it!


Filter Blog

By date: By tag: