heart shaped gummy candy assorted in rows with one candy aside against pink background

Sometimes we are tasked with an update to the service portal widget’s logic. A feature that initially seems to be really simple, no big deal, like add confirmation modal after button click or gather some logs before submitting the ticket. The usual approach would be to simply edit the widget, update the action and submit. But sometimes the widget is protected, has too many dependencies, is used in multiple pages, is too complex, there are already thousand copies of it, you simply don’t like cloning widgets or you want to stay as close to the baseline as possible without touching the OOB artifacts.

I’ve recently found a solution to that issue. It’s not that simple or obvious, but I’ll try to walk you through it as good as I understand it.

The idea

OK, so if I don’t want to alter the original widget, what can I do? Honestly, I have no other options than creating another widget. Now, this will probably blow your mind and turn your world around (as it did with me!) but widgets don’t need HTML to work! With this being said, your mind will probably be like fine, it even makes sense, but how can it help – it’s the widgets world, everything is scoped here, can I even read another widget’s scope from outside?

Of course you can! ServiceNow even has a KB article that will guide you step by step. You can see the examples of retrieving scope data, changing it and running function, including server data refresh in the Advanced techniques section.

Ready to develop…?

Not yet. I told you it was complex. So far we have learned that it is possible to access widget’s scope from outside (browser’s console). But can we do it from a widget? Let’s analyse what we are actually doing:

var scopeRef = angular.element($0).scope();

The code above gives us access to the widget’s scope. With scope, we can easily change widget’s logic by overriding actions and running completely new server scripts. As you can see, we use angular keyword to call element() method. As you can read in the angularjs documentation, it simply wraps a raw DOM element as jQuery element.

Great, now we know that we need to call scope() on wrapped DOM element referencing our target widget. Again, is it doable from a different widget?

Link to the rescue!

Taken from deviantart. The green guy is Link, from Legend of Zelda game series.

You remember that additional script field on the widget record called Link? You’ve probably never used it and you’re wondering why it’s there at all? Well, now you know! In general, it allows you to do some DOM manipulation. You can read more on stackoverflow or in the official docs.

link function allows us to reach the DOM structure of the current widget. With some additional searching and having some knowledge about how widget’s HTML id are generated on service portal (.v + sys_id) we can easily find our target widget. Finally, ready to develop!

Development

This part will be easy.

Client controller

Write a c.init function which will later be invoked by link function. In that init, you must do couple of things:

  • pass wrapped DOM as an attribute
  • get the scope of wrapped DOM
  • override target widget’s function with a new by doing
    targetScope.c.functionToOverride = function(){}
  • remember to include any other required client logic – once you override, this widget’s logic will take over

Server script

If necessary, update the server script. Remember that if overriden function is invoked, your new widget’s server script will be executed, not the overriden one.

Link function

Now, the most important part. You have to do two things here:

  • find your target widget’s DOM
    • remeber about its coded id
    • and you also have current widget’s DOM reference which you can use along with parent() or child() native js functions
  • run controller.init(targetWidgetWrappedDOM)
    • controller is a 4th parameter in the link function and it references current widget’s client controller
    • init is the function you wrote two paragraphs ago

And that’s it!

You can add one more thing to be safe – MutationObserver if you can’t find target widget’s DOM.

Conclusion

As you can see (or as I have recently learned) ServiceNow still has many mysteries to solve and learn. With some general knowledge and code reading ability, it’s esay and satisfying to discover them.

Keep digging. Keep discovering. Keep learning.

Leave a Reply

Your email address will not be published. Required fields are marked *