This article is a supplement to the ServiceNow documentation. For full documentation please refer ServiceNow official website
Checkout our NEW Video Channel you can like and subscribe too!

Introduction

Widgets are a very powerful component in Service Portal.In Service Portal we can created our own widgets.Process data and display any data in the widgets based on our needs.This gives us with infinite choices to design our dashboards.

Creating a new Widget

We can create widget in 2 ways.

  1. By typing widget in the left navigation pane and click new.
  2. By typing service portal in the left navigation pane and click Service portal configuration.

2nd method is preferred

2nd method

Angular JS (1).png

Then click widget editor

Angular JS (2).png Angular JS (3).png

In widget editor we can see below

Angular JS (4).png

Panes
1. HTML template
2. Client Script/client controller
3. Server Script
4. CSS
5. Preview

Tick preview to see the html changes Angular JS (5).png

Also check public widget to make this widget publicly available

The Angular Basics

Service Portal uses angular directive to construct decision logic using controller and html views.We should have a basic understanding for the various directive available.

Angular Directive

1. Ng-click
2. Ng-if
3. Ng-repeat
4. Ng- model
5. Ng-bind

Ngclick

Ngclick is a directive in angular to define functionality on a button or link etc.

In the html Code

<element ng-click="expression"></element>

Here we mention the function name which we want to call inside the ng-click directive Angular JS (6).png

 <div>
  <button ng-click="hello()">
    Click   
  </button>
</div>

Write client script Angular JS (7).png

function($scope) {
  /* widget controller */
  var c = this;
	
	//function
	$scope.hello = function(){
		alert("Hello World");
	}
}

The $scope is the binding part between the HTML (view) and the JavaScript (controller).$scope is an object in Angular that holds all functions and properties.This properties/method can be accessed in the html page. As we have done here for method hello () in html ng-click directive.

hello() is a function. We defined the function in the client script and used it in the html template.

#Below two points are key

We must define all function and variables inside $scope only.
We must define $scope parameter in the root function

Note: Hit the save button (at the top) to see the code changes reflected in the preview. We can also hit cntrl+s to save the widget.

Now check preview pane and click the button to see the alert

Angular JS (8).png

Ng-if

To apply any conditional logic to the html page based on true/false we need to use Ng-if. The condition within the “” of ng-if should evaluate to true/false

Example 1

Write a code in html

<element ng-if="expression"></element>

Angular JS (9).png

<div>
  <span ng-if="show">
    Hello   
  </span>
</div>

Write client script Angular JS (10).png

function($scope) {
  /* widget controller */
  var c = this;
	$scope.show = true;
}

So, the hello message will show in the html Angular JS (11).png

Example 2

Using a condition we can also use a condition like if say number of coins are greater than 0 then show otherwise don’t.

In html we write below code, the condition is if number of coins is zero or undefined we show No coins.If number of coins is greater than 0 we show the number of coins.

In the html Code Angular JS (12).png

Notice that we have {} to express a scope variable defined in the Client Script

<div>
  <span ng-if="coins ==0 || coins == undefined">No coins </span>
  <span ng-if="coins>0"> coin(s) </span>
</div>

In client script Angular JS (13).png

function($scope) {
  /* widget controller */
  var c = this;
	
	//variable
	$scope.coins = 1;
}

In preview we see Angular JS (14).png

Example 3

We can do the same thing using sever side variable.


For server-side variable we have always represent as data.variable in Client/HTML code

In the html Code Angular JS (16).png

<div>
  <span ng-if="data.coins ==0 || data.coins == undefined">No coins </span>
  <span ng-if="data.coins>0"> coin(s) </span>
</div>

In server script Angular JS (15).png

(function() {
  
	data.coins =1;
	
})();

In preview we see Angular JS (17).png

Ng repeat

If we have a list of items and we want to iterate in a loop then we can use Ng repeat.

Example 1

In Server script

Angular JS (18).png

(function() {
  
	data.coinType = [];
	data.coinType.push("gold");
	data.coinType.push("silver");
	
})();

In html

use ng repeat

Angular JS (19).png

<div>
  <span ng-repeat= "coin in data.coinType">
   {{coin}}
    <br>
  </span>
</div>

Where coin is the temporarily variable pointing to current object in the loop

Example 2

We can do the same thing using a variable in client controller. Only difference is we have to use the scope variable instead of data.

In html Angular JS (21).png

<div>
  <span ng-repeat= "coin in coinType">
    {{coin}}
    <br>
  </span>
</div>

In client Script Angular JS (20).png

function($scope) {
  /* widget controller */
  var c = this;
	
	$scope.coinType = [];
	$scope.coinType.push("gold");
	$scope.coinType.push("silver");
}

In preview Angular JS (22).png

Ng bind

If we want to attach a variable from the client script to the html page we have to use ng bind.

Ng bind is uni-directional from client script to the html page.

In html image23.png

<div>
 <span ng-bind="bindCoin"></span>
</div>

In client Script

image24.png

function($scope) {
  /* widget controller */
  var c = this;
	$scope.bindCoin = "All coins";
}

In preview

image25.png

Lets have a look at the unidirectional behaviour

we will use a textarea and bind the value, but because we use bind when we make some changes in the textarea the client script variable will not update because bind is uni directional.

In html

image26.png

<div>
 <textarea ng-bind="bindCoin"></textarea>
  <span>{{bindCoin}}</span>
</div>

In client Script

image27.png

function($scope) {
  /* widget controller */
  var c = this;
	$scope.bindCoin = "All coins";
}

In preview

image28.png

Even if we change in the text area, the underyling will not get updated But instead if we use ng-model with the same example,then we will see it will update the underlying variable.We will ng-model in the next section.

Ng Model

Binds both ways so from html we can update back the variable. This can be used when we submit a form (with latest changes)

In html

image29.png

<div>
 <textarea ng-model="bindCoin"></textarea>
  <span>{{bindCoin}}</span>
</div>

In client Script

image30.png


function($scope) {
  /* widget controller */
  var c = this;
	$scope.bindCoin = "All coins";
}

image31.png

SP Util

Sputil is a inbuild library available that we can use client script.Have lot of ootb function that we can use. Utility methods to perform common functions in a Service Portal widget client script.

Few of the most common functions are

  1. update
  2. recordWatch
  3. addErrorMessage/addInfoMessage

Data flow in widget

widget starts from the server script where the data objects gets populated, then it reaches client where it gets updated by form based user action like save, then in client side the updated data is copied into input object and passed back to the server.

To get the new updated data from the html/client script we need to use the input object in server side.

Data flow in service portal widget.JPG

A typical server to client and back to server have the following flow

  1. Current record is loaded in to data object (say a particular incident details)
  2. The data is then send to client/HTML page for view
  3. Along with that ng-model and ng-click binding occurs for displaying,updating and saving the form state.
  4. User clicks save after updating the description and the event is fired.
  5. Client script calls the SpUtil update to call the server side and request to update the data
  6. The server sides observes there is input object so it understands data has been updated from client side.It saves the updated data to the table

One thing to note here though after save the actual table data gets updated,the widget data object is still holding the old data,so in the text area it will show the old data only

So how do we see updated data?

  1. Ofcourse we can just refresh the page which will force a backend fetch abd it will update the widget data object
  2. A better solution is to set a watcher that can pull information from the server table and update the view

image47.png

Lets check this with an example.

In this example we will load an incident name and short description from sever to client using the data object.

In Server script

(function() {

    var incRec = new GlideRecord('incident');
    incRec.addQuery('number', 'INC0009009');
    incRec.query();
    if (incRec.next()) {
        data.number = incRec.number.toString();
        data.short_description = incRec.short_description.toString();
    }
})();

In html

<div>
  {{data.number}}
 <textarea ng-model="data.short_description"></textarea>
  <button ng-click="save()">Save</button>
</div>

image37.png

Now lets write logic to save the data in the backend using the server.update method.

In client Script


function($scope, spUtil) {
    /* widget controller */
    var c = this;

    $scope.save = function() {
        spUtil.update($scope)
    }
}

Here use the spUtil update method to update in the backend using the input object. So we update our server script as below.

Note that here we update the incident table description from the input object which is passed from the client.

In Server script

(function() {

    var incRec = new GlideRecord('incident');
    incRec.addQuery('number', 'INC0009009');
    incRec.query();
    if (incRec.next()) {
        data.number = incRec.number.toString();
        data.short_description = incRec.short_description.toString();
    }

    if (input) {

        var incRec1 = new GlideRecord('incident');
        incRec1.addQuery('number', 'INC0009009');
        incRec1.query();
        if (incRec1.next()) {
            incRec1.short_description = input.short_description;
          
            incRec1.update();
        }
    }

})();

Now lets update the description in the client html page and see it in the incident table

Before save the description image43.png

After save the description changed

image45.png

Notice that the view is till showing the old data.

image46.png

To see the new data we can refresh the preview or we can use Record watcher, which can dynamically update the data.

In RecordWatch util method we have mention the table name which we want to watch for updates,also we can add any filter, i.e example below we add the ticket number

In client Script


    spUtil.recordWatch($scope, "incident", "number=INC0009009",
        function(name, data) {
            spUtil.update($scope)
        });

The Full code

In Server script

(function() {

    var incRec = new GlideRecord('incident');
    incRec.addQuery('number', 'INC0009009');
    incRec.query();
    if (incRec.next()) {
        data.number = incRec.number.toString();
        data.short_description = incRec.short_description.toString();
    }

    if (input) {

        var incRec1 = new GlideRecord('incident');
        incRec1.addQuery('number', 'INC0009009');
        incRec1.query();
        if (incRec1.next()) {
            incRec1.short_description = input.short_description;
			incRec1.update();
        }
    }

})();

In client Script


function($scope, spUtil) {
    /* widget controller */
    var c = this;

    $scope.save = function() {
        spUtil.update($scope)
    }


    spUtil.recordWatch($scope, "incident", "number=INC0009009",
        function(name, data) {
            spUtil.update($scope)
        });
}

In html

<div>
  {{data.number}}
 <textarea ng-model="data.short_description"></textarea>
  <button ng-click="save()">Save</button>
</div>

Intercommunication between widgets in Service Portal

A Service Portal page can have multiple widgets.To modularize our code we should have multiple widgets and establish communication between them.Below is an simple example to create 2 widgets and communicate between them

Widget 1

widget241120191.PNG

widget241120192.PNG

Widget 2

widget241120193.PNG

widget241120194.PNG

widget241120195.PNG

Read More

Read More

Widget to Widget Communication

    Content