A Beginner’s Guide to ServiceNow’s Service Portal Widgets

Ricky Y.
5 min readApr 29, 2021

--

I look back to when I joined my first ServiceNow partner company. I asked my manager: “What kind of expertise are we missing? What holes could I fill to best benefit the company?” I’ve since added this to the bank of questions that I would ask when being interviewed. Among the answers, the most common is Service Portal.

Disclaimer: I’m simply sharing my story on how I used portal to really show value quickly. This is in no way the bible for portal developers, but rather a good guide to get started.

It make sense. Service Portal is the part of ServiceNow that the customers & end users interact with. It’s visual, interactive, and customizable. Companies want to ensure that the experience is seamless, beautiful, and most importantly, effective. As a developer or admin, portal is a great way to grow your skills in coding.

Service Portal leverages HTML, CSS, and AngularJS. You can also use jQuery on the client side, but I tend to not (also because I’m not that familiar with jQuery). The view itself is broken into a few components: HTML, CSS, Client Script, Server Script, Link Function.

Widget Editor View

As a beginners guide, we’re going into the following topics. This is my opinionated list of things to learn to show the most value

  • HTML/CSS with Bootstrap
  • AngularJS Directives / Filters
  • Communicating from Client to Server

HTML/CSS with Bootstrap

This one is going to be very short. If you’re unfamiliar with Bootstrap, it’s a library of components that come out-of-the-box with portal. It allows you to quickly design widgets that are responsive. Many of the existing widgets in your instance are already built on Bootstrap (version 3.3.7)

With Bootstrap, there are tons of built-in classes. Depending on the requirement, you’ll find yourself finding everything you need through the documentation. One of the most commonly used, in my experience, is the panel class (in later versions, renamed to card). See documentation here.

AngularJS Directives / Filters

AngularJS directives are powerful. They’re essentially markers on DOM elements — and these flags help the compiler add the desired functionality. I’ll be going through a small subset of directives: the ones which I use regularly and remember off the top of my head. There are many many directives, and you should do your own research to find the one that fits your requirement.

ng-if

The super popular conditional directive. It evaluates an expression and if it is true, then the DOM element will be rendered. In the below example, the div is shown only if the expression isTrue is true (lol).

<div ng-if="isTrue">This text will show </div>

ng-repeat

This directive is used to repeat DOM elements based on an array. See example below

//HTML
<ul>
<li ng-repeat="person in people | orderBy: 'age'">
{{person.name}}
</li>
</ul>
//Client Script
api.controller=function($scope) {
/* widget controller */
var c = this;

$scope.people = [{
name: 'Bob',
age: 27
},{
name: 'Joe',
age: 26
},{
name: 'John',
age: 28
},{
name: 'Alex',
age: 27
}]
};

This will output <li> tags for each item in the specified array. You can access the object people and extract each item into person. As a little add-on, you can also add a filter to order the list. In this scenario, we’re ordering it by ascending age.

ng-click

This directive is similar to onclick but is more powerful. You can connect this to your client script to trigger functions. See below:

//HTML
<button ng-click="onClick('hello')"> Click Me </button>
//Client Script
api.controller=function($scope) {
$scope.onClick = function(name){
console.log(name);
}
}

ng-class

This directive allows you to dynamically set CSS classes on an element by binding an expression. The documentation explains it really well and shows use-cases: see here.

ng-model

This directive allows you to bi-directionally bind a text element to a variable. See below

//HTML 
<div>
<input ng-model="name" type="text" id="name"/>
</div>
<div>
<div>
{{name}}
</div>
<button ng-click="onPress()">
Press Me
</button>
</div>
//Client Script
api.controller=function($scope) {
$scope.name = "Rick"

$scope.onPress = function(){
console.log($scope.name);
}
};

Note the following:

  • ng-model binds to name, which is found on the client script.
  • the function for onPress() accesses the $scope.name and will always get the most up-to-date value
  • The text in the second div will always match what is inside of the input box.

Communicating from Client to Server

This topic is a big one. How do we communicate between the client, template, and server?

Your client-side needs to be notified when the an action is submitted and should send that data to your server to process.

To begin, we need to familiarize ourselves with the two objects: input and data.

input is the object that the client uses to communicate with the server.

data is the object that the server uses to communicate with the client.

How do we send the data from client to server?

On the client side, we’re able to call functions to update the server. The two I use are: server.get() and server.update(). This is called on your controller, so to use it you would use something like this.server.update() or c.server.update()

What’s the difference, you ask? this.server.get() allows you to pass in an object whereas this.server.update() takes what the ng-models are bound to. They essentially do the same thing, so use whichever one you believe to be best fit for the requirement. From these functions, you’ll receive a response which you can parse for the data object. See example below:

//HTML
<div>
<input ng-model="name" type="text" id="name"/>
</div>
<div>
<div>
{{name}}
</div>
<button ng-click="onSubmit()">
Press Me
</button>
<div>
{{c.data.message}}
</div>
</div>
//Client Script
api.controller=function($scope) {
/* widget controller */
var c = this;
$scope.name = "Rick"
var data = {
name: 'Any data',
power: '9000'
};
$scope.onSubmit = function(){
c.server.get(data)
.then(function(res){
c.data = res.data;
})

}
};
//Server Script
(function() {
data.message = "Initial Message to Client"
if(input){
console.log(input);
data.message="New Message from Server";
}

})();
Before clicking the button.

Click the button, which should trigger a call to the server to update the data.message object. We then take this message and copy it to our c.data object, which will also update the HTML template.

This example is super simple, but should give you an idea of how to pass data from the client to the server.

I hope you enjoyed this brief article! ServiceNow’s Service Portal is such a powerful tool to use. Understanding how to build custom widgets is not only fun but it will greatly help you fill the holes in your company.

Cheers!

--

--

Ricky Y.
Ricky Y.

No responses yet