Logging Objects in ServiceNow

I believe that I’ve got a post from a ways back talking about how to log an object in ServiceNow. Since then, I’ve realized that there are two much easier ways to log out on object.

You can stringify the object before trying to log it, or you can use the JSUtils.logObject() method.

Here is a quick demo script:

var myObject = {
“name”: “Object1”,
“number”: 1
};

var stringObject = JSON.stringify(myObject);
gs.log(“My Test. myObject: ” + myObject);
gs.log(“My Test. stringObject: ” + stringObject);
JSUtil.logObject(myObject);

Here is the output:

 

 

 

 

Here is the official documentation for the JSUtil.logObject method:

https://developer.servicenow.com/app.do#!/api_doc?v=newyork&id=r_JSUtil-logObject_O_S

getXML() and getXMLWait()

I have a common pattern I use where I have a server-side script include that does all of the heavy lifting, which then subsequently needs to be accessed by something on the client script.

Using a GlideAjax script include allows you to take input from the client side of things and pass it to the GlideAjax which in turn passes it to your server-side script include.

This works well on the whole, but can run into problems if you have something on the back end that isn’t instantaneous–like an API call. In those scenarios, you can see instances where the client script has moved on and is acting as though it has the data from the server-side script include before the data is actually there.

In modern JavaScript I would handle that by using async/await, but it took a bit for me to figure out how to deal with it inside of ServiceNow.

The correct way to do that is with getXMLWait(), or by calling getXML() and then passing in the name of the function you want to run after the server-side stuff has run.

Note, you have to pass just the name, not the name and (), so if you had

function doSomething() = {

     console.log(“Hello World”);

}

and you wanted to add a callback to a getXML(), then you would use:

getXML(doSomething);

Determining what makes up a Performance Analytics Dashboard

This is going to be one of those posts that seem like common sense to some people, but I recently needed to figure out which reports made up a particular performance analytics dashboard, and I didn’t find anything that jumped out at me online.

It turns out that the way to find this out is to go to the list of dashboards (pa_dashboards.list).

Then click the ‘Launch Dependancy Assessment’ ui action. This will pull up a list of tabs and the reports that are on each tab, allowing you to find out what makes up the dashboard.

ServiceNow Workflow Scratchpad (Break)

I recently had a project where I wanted to use a looping workflow that would continue around the loop until some criteria was met.

For various reasons, I was going to find out whether or not a given loop was done before I actually reached the if statement that was designed to break the execution flow out of the loop and allow the workflow to move on.

Given that, it seemed sensible to to use the scratchpad to set a variable that I could then check against when it came time to break out of the loop. That would save me having to do a GlideRecord query at the decision point to determine whether or not it was time to exit the loop.

I wrote the code, and when the workflow detected that it had gotten to the point where the loop wasn’t supposed to continue, I set “workflow.scratchpad.break = true”, at which point my workflow broke and started behaving erratically.

It’s possible that something else was happening as a result of setting the break variable to true, but as nearly as I can tell, doing that actually dumped the values in the scratchpad, leaving me with undefined instead.

I’ve done some checking to try and see if that is documented somewhere, but haven’t be able to find anything to date. It makes sense that break could end up being some kind of reserved term given its use generally inside of Java and Javascript.

For now, use workflow.scratchpad.break in your workflow at your own risk.

NodeJS Testing Framework beforeEach() vs beforeAll()

I’ve been using the Jest testing framework in a side project. One of the areas I needed to test required that I populate data in my MongoDB database so that there was something for the tests to run against.

I had some debate in my mind between using beforeEach(), which does the database population step before each individual test is executed (once for each test), or using beforeAll(), which does the database population step one time before the tests are run collectively.

BeforeAll() seemed like the more efficient–and therefore quicker–way to do things because it would involve fewer calls to the database, but I ran into a circumstance where that was making writing a couple of the tests more difficult.

In testing however, I found that there wasn’t any consistent difference in speed between using beforeEach() and using beforeAll(). I don’t know if that’s because Jest is running the tests asynchronously and therefore the wait while the database is populated is mostly overlapping for each of the tests, or if Jest is doing something where it doesn’t actually run the beforeEach on tests that don’t read from the database, or if there is something else entirely going on there.

The key takeaway for me was that it didn’t matter (from a performance standpoint) whether I used beforeEach() or beforeAll(). As a result, I’ll be using beforeEach() because it makes writing tests slightly easier.

Clearing Your ServiceNow Cache

This week I had an instance where I created a custom table, and then had to come back and add an additional field/column to it. After doing so, I could no longer get the table to display in list view.

Other users were still able to see the table and the data on it, so I knew that it was still there.

In the end, running cache.do in the application navigator did the trick of clearing my cache and allowing me to see the table.

ServiceNow Closing a GlideDialogWindow From a Script

In my previous use cases where I needed to use a UI Page as a modal on a form from inside of ServiceNow, I was just displaying information.

That meant the job of closing the modal/UI Page rested squarely on the shoulders of the user.

In my most recent project (unfortunately something that will have happened months previously by the time this post is published), I needed to have the UI Page be close automatically after the user clicked on a button.

The proper line of code to close a dialog window is:

GlideDialogWindow.get().destroy();

That was fairly easy to find, but I was surprised to find that you can’t just call that anywhere from inside of the client script on the UI Page.

I’ve seen in the past some instances where the call stack inside of ServiceNow doesn’t seem to behave quite the way I would expect it to based off of my experience with other JavaScript environments. I can’t point to any specific examples, or remember for sure what I was working on when I ran into the odd behavior, but that recollection that I’d had problems previously caused me to place the .destroy() call inside of my callback function.

(I was using a GlideAJAX to drive back-end behavior from the UI Page, which necessitated the use of a callback function to parse out the XML response from the GlideAJAX.)

It appears that you’ve got to place the .destroy() call inside of the main client script function inside of your UI Page for it to properly close out the UI Page.

In my instance, placing that .destroy() call after the .getXML(callbackfunction) call meant that the callback function had been cleared off of the call stack before execution flow got to the .destroy() call, so everything worked, but I was surprised that I couldn’t call .destroy() from inside of the callback function.

Troubleshooting Calling a UI Page from a UI Action

As I discussed in my last post, I’ve worked with UI Actions to call UI Pages previously. However, during this most recent project, I was seeing odd behavior where when I would click on the UI Action, the page would be redirected to the page where the UI Page is defined rather than just staying on the current page and popping up a modal.

Even more surprisingly, when I hit the back button to go back to the form from which I’d click the UI Action, I would see the UI Page pop up as a modal.

As it turns out, this behavior is caused when you haven’t defined the UI Action in question as being client callable.

So, if you ever have a UI Action that is redirecting to the UI Page rather than displaying the pop-up, double check that you’ve clicked the ‘client’ box on the UI Action definition.

The Context of UI Pages From GlideDialogWindow

I recently found myself needing to have a UI Action pop up a modal which would accept user input and then go perform various actions depending on what user input had been received.

I created the UI page, and then rendered it using something like this:

var dialog = new GlideDialogWindow(‘UI_Page’);
dialog.setTitle(“Page Title”);
dialog.render();

That is fairly basic, and is something that I’ve done previously, but something that I hadn’t realized before now is that in the client script of the UI Page, it’s possible to use g_form calls.

In essence, it appears that a UI Page (at least one called from a UI Action which is in turn called from a form) has access to the same context/namespace as the underlying form which was used to call the UI Action.

Now that I’ve written that down, I’ll remember it for the next time that I need to do something more complicated with a UI Page.

ServiceNow Copying Date-Times In A Script

On a recent project, I needed to copy some date-time fields from one record to another.

I was using a server-based script include to do the copying, and assumed that I would be fine with a:

newRecord.created_at = oldRecord.getValue(‘created_at’) kind of construction.

What I found in practice though was that the date-time field on the copied record was 6 hours different than the field that had been copied from the original record.

This struck me as likely being due to a GMT vs local time kind of issue. That didn’t make a ton of sense given that we should just be copying one number from the back end to another field, also on the back end. Logically, I wasn’t expecting it to do any kind of changing of either of those two numbers to account for the user’s time setting, but apparently I was wrong.

Construction like this:

newRecord.created_at = oldRecord.getDisplayValue(‘created_at’)

Is returning a new record where the date-time field matches the original.

My best guess at this point is that ServiceNow runs some kind of middleware anytime you save a date-time (even on the back end) which takes whatever the user inputs and converts it to GMT.

In the original code, this meant that I was pulling GMT out of the database on the original record, and then that time was being shifted 6 hours before it was saved on the new record.

By getting the display value of the old record, we shifted the GMT time to local time, and then passed the local time to the middleware function which shifted it back to GMT before saving the new record to the database.

In short, any time you want to copy date-times, you need to use a .getDisplayValue() on the field you’re copying in order to have the value being saved in the new field match up with the old field.