arthuroliveira
ServiceNow Employee
ServiceNow Employee

"Single-Page Applications are Web apps that load a single HTML page and dynamically update that page as the user interacts with the app. "

Microsoft Magazine

For this example we will be using ui-router to manage state and what is displayed to the user but with this approach you could use any state manager.

Let's call our project Hello World

Some information about our project

Portal:

Title: Hello World

Url suffix: helloworld

Homepage: helloworld_homepage (an empty page that we creating the portal)

find_real_file.png

Step 1

First let's download the library (https://github.com/angular-ui/ui-router) and create a UI Script with its content . The minified version is recommended.

find_real_file.png

Step 2

Let's create a UI Script that our application will rely on. That UI Script can be used to create factories, services, filter, etc. Basically any angular 1 component.

I'll name our UI Script helloworld-uiscript. I find that appending uiscript to the name makes it easier to identify it later on when we start working with widgets as well.

In our UIScript I'll start creating an angular module called helloworld and adding ui.router as dependency. This is pure angular code and it should look   very familiar to angular developers

(function (angular) {

      angular.module('helloworld', ['ui.router'])

})(angular);

Next let's define our states. For this demo we are creating 2 states. I'll try to keep it simple naming it homepage and detail but for your application make sure your state name reflect the state of your application.

IMPORTANT Please note some states are already being used by service portal and it will break if you try to create a state with the same name, that's why I avoided using state1 and state2 and used homepage and detail instead

Lets add a configuration block to our helloworld application. We will also inject $stateProvider which is provided by uiRouter and define our states.

(function(angular) {

      angular.module('helloworld', ['ui.router'])

              .config(function($stateProvider) {

                      $stateProvider

                              .state('homepage', {

                              })

                              .state('detail', {

                              })

              })

}])(angular);

Next we need to define what content (template) we will display for each state. We have couple options here.

Option 1:

We can define our template inline using the template property. It would look somewhat like this:

.state('homepage', {

template: "<h1>Hello World Title - Homepage</h1>"

})

This template property could become massive depending on what our state would display, so let's take a look at some other options

Option 2:

UI Pages! As alternative to option 1, we could use the property templateUrl to point each state to a UI Page. It would look like this:

.state('homepage', {

templateUrl: "homepage.do"

})

Option 3:

TemplateCache! We can also use templateCache to point to a template ID that we will define later on. IT would look like this

.state('homepage', {

templateUrl: "homepage"

})

Since option 1 and 2 is pretty straightforward I'll implement our helloworld demo using Option 3.

Your UI Script should look like this at the end

(function (angular) {

      angular.module('helloworld', ['ui.router'])

              .config(function ($stateProvider) {

                      $stateProvider

                              .state('homepage', {

                                      templateUrl: "homepage"

                              })

                              .state('detail', {

                                      templateUrl: "detail"

                              })

              })

})(angular);

UPDATE:   SP ng-template might be a better solution for a production application but the concept is the same

Step 3:

Now lets create our custom widget that will wrap our application, add the proper dependencies and add it to our homepage.

You can create the widget using the widget editor view or servicenow form. I'll use the widget editor by going to /sp_config?id=widget_editor but we will need to switch to the form view to add the dependencies

For this widget I'm going to name it helloworld-uiview

HTML

Let's start creating our cached templates defined in the uiscript (state1 and state2) then we will add a ui-view directive provided by ui router. Your code should look like this

<script>

  <h1>Homepage View</h1>

  <a ui-sref="detail" class="btn btn-primary">Go To Detail View</a>

</script>

<script>

  <h1>Detail View</h1>

  <a ui-sref="homepage" class="btn btn-primary">Go To Homepage View</a>

</script>

<ui-view></ui-view>

CLIENT SCRIPT

In the client script we need to define our default state AKA home state. For this we need to inject $state, provided by ui router

IMPORTANT: Later in the process we are going to access a page called $spd.do . This page relies on $state to work, so we need to write some work around to stop $state manipulation   for when accessing this page

Your code should look like this:

function ($state,$location) {

  if ($location.path().indexOf('editor') != -1) {

    return;

  }

  $state.go('homepage');

}

No Server side script, SCSS and link function are needed for this example, now let's switch to the platform view by clicking on the hamburger menu on the top right

find_real_file.png

Setting up Dependencies

Scroll down to Dependencies and let's create a new dependency (sp_dependency)

Name: helloworld Dependency

Include on page load: yes

Portals for pageload: helloworld

Angular module name: helloworld (defined in our ui script)

Save instead of submitting so we stay on the same page and we can add the files dependency

Now lets create 2 new JS Includes. One for our helloworld-uiscript and another for ui router. It's important that the Order field for UI router is smaller than helloworld-uiscript since our uiscript injects uirouter as dependency

Display Name: UI Router

Source: UI Script

UI script: ui router

Display Name: UI Router

Source: UI Script

UI script: helloworld uiscript

find_real_file.png

Step 4

The alst step is adding our helloworld-uiview to the homepage.

We can do this by going to /$spd.do

Final Result

gif-generated.gif

You can view a live demo here:

https://empaoliveira.service-now.com/helloworld

I hope it helped!

Soon I'll post a part 2 where I'll explain how to develop single page app with deep linking so you can use the history tab to go back or send a user to a specific state.

Thank you

4 Comments