UI Action Client/Server Interactions (without AJAX!)
Do you hate AJAX Script Includes with a fiery passion? I do – they're ugly, error-prone, and full of annoying boilerplate! I consider the unfortunate reliance upon AJAX Script Includes within UI Actions to be one of ServiceNow's foundational sins. It simply should not be this hard to achieve basic user interactions when using perhaps the premiere design verb available to us within ServiceNow.
Frequently stumped by this issue, we've poured much time and thought into existing solutions and have created a novel solution worthy of a new place in the pantheon of UI Action design patterns. I'll reveal all below... but in order to get there we'll first need to cover the existing options & limitations. Those already familiar should feel free to skip ahead past... The Managerie. Those simply searching for copyable templates can even skip directly to the bottom!
A Menagerie of Extant UI Actions
Server-Side: The Conventional Solution
The typical UI Action is easy to understand: simply click a button and some Server code gets triggered. These are the backbone of the UI Action paradigm and we'll call them "Server-Side UI Actions".
Designers should use Server-Side UI Actions whenever possible, because all other approaches are necessarily more complex and therefore less desirable. The only reason to be using any other pattern – ours included – is if design requirements exceed the inherent limitations of Server-Side UI Actions. These limitations are born of the inherent architecture of Server-Side UI Actions, illustrated below...
As you can see, there are zero opportunities for the designer to insert user-facing interactions during the moment between UI Action activation and form submission. It's already too late by the time the "Server Script" in our diagram has a chance to run.
This limitation precludes many useful design techniques, such as:
- Modifying the form input without immediately submitting changes.
- Interactive input validations without forcing the user to submit & pray .
- Inserting additional prompts/dialogs into the submission design flow.
Client-Side: A Different Key For a Different Lock
Client-Side UI Actions completely flip the script. They don't cause any Server-side code to run when clicked. Nothing even gets submitted to the Server!
This is actually quite handy for the intended use-case: providing simple shortcuts and on-page doodads which make the user's life easier. It's a great pattern if design requirements don't demand any interaction with the Server...
When you get down to it, the core Server-Side and Client-Side UI Action types actually have very little functional overlap. This is something of a problem, because it is extremely common for designers to desire functionality from both paradigms in the same UI Action!
"Combo" UI Actions: Two For One... Sort Of?
"Combo UI Action" is a term of art invented for the purposes of this article. It's an undocumented yet common variant of the Client-Side UI Action which cleverly sneaks in the ability to execute Server-Side code – almost as if there were actually two different UI Actions belonging to the same button: one Client-Side, one Server-Side. Emphasis on "different"! There's a lot to unpack here, so let's first take a peek at the code...
This technique allows for writing some code which runs client-side and some code which runs Server-Side. It sounds more useful than it actually is – the Server-Side code and the Client-Side code are completely isolated from each other and cannot communicate!
This approach is useful if the intent is to attach some Client-Side pre-validation to an otherwise independent Server-Side UI Action... but it completely falls flat if, for example, the designer wishes to prompt the user for input and then handle that user-provided input via Server-Side code. It really is like have two completely separate UI Actions attached to the same user-facing button – the streams cannot be crossed!
Time for a detour: how does this trick actually work? This is important: even if you've used this pattern before, it's important to understand the underlying mechanics!
Let's start by examining how Server-Side UI Actions internally function:
- User clicks the button.
- Button triggers the following client-side code
gsftSubmit(this)
- The g_form is HTTP POSTed to the Server.
- Code in the "Script" field is triggered on the Server to process the form data.
Steps 1-3 are abstracted away and hidden from the designer, but they exist nevertheless! Now that we understand the mechanics, we can start to appreciate how surprisingly similar Client-Side UI Actions are under the hood:
- Code in the "Script" field is smuggled into the HTML page during initial load.
- User clicks the button.
- Button triggers client-side code from the "On Click" field
(traditionally, this is used to call one of the functions smuggled in during Step 1)
Client-Side UI Actions essentially have two special traits:
- A copy of your "Script" code gets smuggled into the HTML page.
- Instead of defaulting to
gsftSubmit(this)
it uses your "On Click" code.
That's it! These two changes alone are what make the two types different. Should one desire, it's entirely possible to create a fake "Client-Side UI Action" that's actually identical to a Server-Side UI Action by simply setting the "On Click" field to gsftSubmit(this)
– recall that this is what would've happened automatically were "Client" left unchecked!
Technically this hack does cause an ugly looking error to pop up in the browser console (it tried and failed to run some smuggled Server-Side code)... but we can get around the issue if we just wrap the Server-Side code in a protective IF statement!
Yup. That's the origin of the weird if (typeof window === 'undefined')
. Neat!
AJAX: The Only Route to True Interactivity?
Time for the elephant in the room. All of these patterns are nice... but they don't actually handle the most common use-case for Client-Side UI Actions: prompting the user for input and then using this input in Server-Side code. Historically, this has been the stomping ground of what we'll call "AJAX UI Actions".
"AJAX" in the context of ServiceNow specifically refers to a type of Script Include which can be remotely triggered from Client-Side scripts via the GlideAjax API. It's the bog-standard approach to writing Server-Side code which can be remotely executed via Client-Side scripting.
Frustratingly, adding even a small amount of AJAX to a given UI Action can double or even triple total lines of code. Perhaps even more annoyingly: AJAX Script Includes are slow – UI AJAX Actions can be forced to wait for several seconds mid-execution while the Server thinks!
Despite these flaws, it is undeniable that AJAX Script Includes are incredibly useful tools whenever a requirement to dynamically interact back-and-forth with the Server based on user input arises...
Even so, isn't it kind of overkill if all that's needed is a one-way conversation that starts on the Client-Side and ends on the Server-Side? Why can't there be a happy middle with the simplicity of the "Combo UI Action" pattern for those usecases?
"One-Way" UI Actions: A New Way
We are proud to present a novel UI Action design pattern which achieves exactly this: the simplicity of "Combo UI Actions" + the Client/Server communication. A sort of "One-Way" connection which enables collecting user input on the Client-Side and then punts it over to the Server-Side for processing!
We've effectively extended the aforementioned "Combo UI Action" solution by exploiting the HTTP form submission as a medium for data transport. This tweak eliminates the single greatest limitation of the "Combo UI Action" and unlocks the ability to elegantly handle many User/Server interactions which were previously only possible via AJAX Script Includes!
As you've probably noticed, this new approach brings new limitations:
- Higher complexity than the traditional "Combo UI Action" pattern.
- Server-Side only starts after Client-Side ends – No back-and-forth.
In other words: this isn't a perfect solution – don't reach for it unless it fits the usecase! Some rules of thumb to consider:
- If it's not necessary to pass data from Client-Side to Server-Side, use the simpler "Combo UI Action" pattern.
- If it's necessary to make multiple request/interaction cycles within a single UI Action, use the more powerful "AJAX Script Include" design pattern.
Copyable Templates 🤓
The initial example presented is designed for maximum compatibility – it works regardless of whether the UI Action is present on a list or form page at the cost of extra boilerplate. The required boilerplate is halved if you don't need list compatibility!
Templates for common usecases such as Form-Only, List-Only, and Form+List are available for copying via this gist.