ServiceNow: AngularJS UI Page template

AngularJS is used to build many of the default apps within ServiceNow and is a key technology in the Service Portal. You can also use ServiceNow to develop your own custom AngularJS applications that take advantage of the underlying ServiceNow platform.

This article provides a basic AngularJS template for use in a UI Page. This can be used as a starting point for creating a basic AngularJS application in ServiceNow. I also show an example of how to use UI Page reference fields with your AngularJS app.

Basic AngularJS template

HTML

<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
    <div ng-app="myApp" class="ng-cloak">
        <div ng-controller="myController" ng-init="">
            {{message}}
        </div>
    </div>
</j:jelly>

Client Script

var angularApp = angular.module('myApp', []);
angularApp.controller('myController', function($scope) {
    $scope.greeting = "Hello from Angular!";
});

Example using Reference field

Reference fields can be used in your UI page as you would normally, then bound to a function within your AngularJS application scope using a helper function. Here’s an example using Bootstrap for styling.

HTML

<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"></link>
  <style>
    body,input,button {
      font-size: 11pt !important;
    }
  </style>
  <div ng-app="myApp" class="ng-cloak">
    <div id="myController" ng-controller="myController" ng-init="">
      {{greeting}}
      <div class="col-sm-12">
        <div class="form-group is-required col-sm-8">
          <label for="incident_ref" class="control-label col-sm-4">
            Select an Incident
            <span id="mandatory_mark" class="required-marker" />
          </label>
          <span class="col-sm-8 form-field">
            <j:set var="jvar_onchange" value="onIncidentChange()" />
              <g:ui_reference name="incident_ref" id="incident_ref" table="incident" query="active=true" completer="AJAXTableCompleter" columns="number" />
            <j:set var="jvar_onchange" value="" />
          </span>
        </div>
      </div>
      <div>Number: {{incident.number}}</div>
      <div>sys_id: {{incident.sys_id}}</div>
    </div>
  </div>
</j:jelly>

Some things to note with the above HTML:

  • The <div> with the ng-app attribute now has an id attribute as well. This is used to get the angular scope.
  • The <g:ui_reference> element can be used as you normally would, but we’ve wrapped it within <j:set var="jvar_onchange"> tags so we can set it’s onchange attribute.
  • The onchange attribute is assigned to the function onIncidentChange()

So whenever the referene field changes, the normal javascript function onIncidentChange() will be invoked.

Client script

var angularApp = angular.module('myApp', []);
angularApp.controller('myController', function($scope) {
    $scope.greeting = "Hello from Angular!";
    $scope.incident = {};
    
    // Fires when Incident reference field changes
    $scope.onIncidentChangeNg = function() {
        $scope.incident.sys_id = gel('incident_ref').value; // sys_id of the Incident
        $scope.incident.number = gel('sys_display.incident_ref').value;
    };
});
// Called on change of "Incident" UI Reference
function onIncidentChange() {
    // Get the scope
    var scope = angular.element(document.getElementById("myController")).scope();
    scope.$apply(function () {
        scope.onIncidentChangeNg();
    });
}

Some things to note here:

  • The onIncidentChange() function is invoked by the reference field when it is populated.
  • The Angular scope is retrieved using the id attribute added into the HTML (see notes above).
  • A function onIncidentChangeNg within the AngularJS scope is invoked

I’ve named the AngularJS function onIncidentChangeNg() to make it clear which function is called from where, but there is no reason this can’t also be called onIncidentChange().