Upgrade: Jakarta

ServiceNow Jakarta Widgets: Sorting out UI Sortables

In the hustle and bustle of wrapping up deliverables on a project, I came to the last item on my list for a Release Management Go-Live. There was one nice-to-have feature I had discussed doing for my customer and I couldn’t help myself but want to deliver it. We had discussed the ability to sort and re-order tasks in a Release Phase using drag-n-drop in a list view. Because Release Plans tend to change as they develop, it would be swell if the Release Management team could change their plans as simply as re-ordering them on list.

You see, Release Tasks have an Order field. But Out of Box there’s not much going on with this field; it isn’t on any of the default views and it isn’t populated by default. It seems to be begging someone to come along and make use of it.

I started by writing the supporting code to suggest the next number in sequence on a new task re-ordering the Planned Start / End times based on Planned Duration, which was all really fun GlideDateTime and GlideDuration math. (if you like performing the JavaScript math involved with these datatypes, please seek professional help!) What my customer really wanted, and I agreed, was the ability to reorder the Implementation Release Tasks the same way we can move tasks around on Visual Task Boards. (VTB)

VTB’s are designed to sort from a field like Task State, where there are perhaps 3 or 4 choices you can move the tasks between. Using a VTB with an Integer field like Order, even if it did work, would result in the tasks scrolling far off the screen horizontally. There didn’t seem to be any way to adjust VTB to work with a custom index or order field anyway, so there was no obvious means to make use of the Visual Task Board here.

I checked with a co-worker and he suggested the somewhat legacy Planning Board feature to see reordering tasks in action. Planning Boards would allow the user to add and reorganize tasks for Projects, with some clunky drag and drop ability and blocky tables. The bad news was that this code only (barely) worked in List V2. Since one of my favorite features is List V3 where live updates are available, this wasn’t an option I could be satisfied with. Nonetheless, I deciphered the UI Pages involved to see that the UI Action calls a class named ListSortWindow. ListSortWindow is a class that contains some of the drag and drop functionality we were looking for.

To figure out what this non-documented class was doing, I needed to read and copy that code into my growing stash of includes by using the Developer Tools of any modern browser and then loading [MY_INSTANCE}/scripts/classes/sort/ListSortWindow2.js in a browser and saving it. I tried to make the script work in List V3, where we had agreed the Live Updates would provide a decent means to follow and perform the work of each Release Phase.  Unfortunately, List V3 did not like ListSortWindow.

After that, I tried posting a question on the Community asking about drag-n-drop, in the hopes that a kind passerby would be willing to share their genius with me. The only response I got was to open a feature request, so I tried that next.

By this point, I had burned a few cycles with little progress. I decided that perhaps I should take a stab at writing it myself for List V3. I knew that List V3 meant that I would be working in Angular, so I took to the interweb searching for “angular drag and drop.” I landed on ng-sortable (https://github.com/a5hik/ng-sortable) and I set about trying to add the feature to one of the list widgets.

I knew how to start out: take an existing widget, clone it and any dependencies and then start editing. I decided to clone the Data Table widget to create Data Table Sortable. I created a dependency for ng-sortable and confirmed when I loaded the widget inside a test page that the include was present. I also added the directives dictated in the readme.

Things were finally starting to come together, but when I tested my new baby widget, there were unexpected results. I could manage to drag but I could achieve no drop.

In conferring with one of our Angular experts here, we noted that other platform pages use ui-sortable, so once again I took to the interwebs.

I found in the developer notes for ui-sortable that nested ng-repeats aren’t supported. I had been working in the html template long enough to be aware that the Data Table widget uses one ng-repeat for the outer rows of the list, and a nested ng-repeat for the columns (fields) inside each row.

This is when I decided that SN surely had come up with a solution to this issue, and now I was curious to see what that solution is. I took to my developer instance heading to our trusty Visual Task Boards to inspect the page, hoping for clues on how SN achieves sortable / drag and drop between the swim lanes. I was pleased to discover the following:

It appears that sortable within the platform is currently a mix of angular and jQuery. I could now abandon my attempts to wedge ng-sortable into my widget, and instead make use of the wheel that was already invented. In this case, we created a Widget Dependency using the script loaded from a URL.

First create the dependency:

Then load the widget in a Portal Page and confirm the include:

In reviewing the VTB source code I noted the required directives…

I changed the directives to match ui-sortable and things began to work much better. (Some CSS code was required.)

The options are bound to ui-sortable as an object containing the update function, which is called when a drop is completed.

Now we can watch as the drag and drop re-orders the tasks and resets the Planned Start times.

Aside for the fact that this code actually works and provides value to the Release Managers who need to be able to manage flexible Release plans, there are definite benefits to using code provided by the platform. We don’t have to worry (as much) about platform changes making an external include obsolete. We also know that since this code is provided by the ServiceNow platform, it should work cleanly with the rest of platform. This means we don’t have to worry about unexpected behaviors and collisions.

Continue Reading