The Now Platform® Washington DC release is live. Watch now!

Help
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Sush3
ServiceNow Employee
ServiceNow Employee

Widgets are a very powerful component in Service Portal. A Service Portal page can have multiple widgets or just one widget. If your page is complex, It is a good practice to divide its functionality into multiple widgets to keep the implementations separate. When dealing with multiple widgets on a page its good to know how to communicate between them.

Folks familiar with angularjs might have already come across $emit, $broadcast and $on. This is exactly what we will be using today talk to other widgets.

We will start by creating a simple page with four widgets.

  • Widget 1: Has three buttons, clicking on these buttons shows its corresponding widget.
  • Widget 2/3/4: Shown/ Hidden based on button click in widget 1

Step 1: Create a portal or use an existing one.

                If you have a portal you are already working with just use that or to create a sample one to play with.   Attaching a screenshot of my example portal.

Screen Shot 2016-06-26 at 12.24.25 AM.png

Step 2: Create a Service Portal page and add that to your example portal.

                For demo purpose, I am going to create a new page give it a name/id and add that to my portal we created in the previous step.

Screen Shot 2016-06-26 at 12.32.10 AM.png

Now let's start creating our widgets.

Step 3: Create Widget 1

Click on widgets under "Service Portal" application menu (or you can also create widgets using widget editor). Create a new widget by clicking on the new button.

                  Below is the example widget I have created.

Screen Shot 2016-06-26 at 12.38.32 AM.png

Please use the below snippets to create your widget

HTML:

<div>

<!-- your widget template -->

  <div class=" pill-background row">

      <div class="each-pill" ng-class="{'active':c.selectedPill == 'requests'}" ng-click="selectPill('requests')">

            <i class="fa fa-2x fa-list "   aria-hidden="true"></i>

              <p class="remove-margin">All Requests</p>

      </div>

      <div class="each-pill" ng-class="{'active':c.selectedPill == 'create'}" ng-click="selectPill('create')">

         

          <i class="fa fa-2x fa-wrench " aria-hidden="true"></i>

          <p class="remove-margin">Create Request</p>

      </div>

      <div class="each-pill" ng-class="{'active':c.selectedPill == 'contact'}" ng-click="selectPill('contact')">

         

          <i class="fa fa-2x fa-phone "   aria-hidden="true"></i>

          <p class="remove-margin">Contact</p>

      </div>

  </div>

</div>

As you can see div "each-pill" has ng-click to function "selectPill". There is ng-class to show the difference between selected/unselected pill

Client Controller:

function($rootScope,$scope,$timeout) {

  /* widget controller */

  var c = this;

  c.selectedPill = 'requests'; // When page loads, default pill selected

  /*broadcast to other widgets after waiting for 500 milliseconds,

      just to make sure other widgets are loaded and ready to listen when we broadcast.          

  */

  $timeout(function(){

  $rootScope.$broadcast('showHideWidget', 'requests');

  },500);

  //broadcast the selection when ever cliked on each pill

  $scope.selectPill = function(selection){

  c.selectedPill = selection;

  $rootScope.$broadcast('showHideWidget', selection);

  };

}

In script above I have used $rootScope.$broadcast to notify other widgets, we can either use $rootScope.$broadcast or $rootScope.$emit.

Keep in mind $rootScope.$broadcast will notify all $rootScope.$on and $scope.$on

$rootScope.$emit will only notify $rootScope.$on.This is the syntax $broadcast/$emit

//firing an event

$rootScope.$broadcast('myCustomEvent', 'data');

data can be a JSON object, in our case its just a string.

//listening for an event

$scope.$on('myCustomEvent', function (event, data) {

  console.log(data); // 'Data to send'

});

OR

$rootScope.$on('myCustomEvent', function (event, data) {

  console.log(data); // 'Data to send'

});

CSS/SASS:

//Make sure sp-landing-back.jpg is in images table

.pill-background {

      background: url(sp-landing-back.jpg) no-repeat center center fixed;

      -webkit-background-size: cover;

      -moz-background-size: cover;

      -o-background-size: cover;

      background-size: cover;

      height: 300px;

      display: flex;

      align-items: center;

      justify-content: space-around;

      .each-pill {

              &.active {

                      color: #c70000;

              }

              height:150px;

              width:200px;

              background:#ddd;

              padding:50px;

              text-align:center;

              border-radius:4px;

          cursor:pointer;

         

          p{

            margin-top:5px;

          }

      }

}

.color-red {

      color: #c70000;

}

.remove-margin {

      margin-bottom: 0px;

}

After populating your widget with above code, go ahead and save it.

Widget 1 looks like this and you can see three pill boxes, clicking on them will emit/broadcast information to all other widgets. By default "All requests" pill is selected when the page loads.

emit.png

Step 4: Create Widget 2 (All requests)

Screen Shot 2016-06-26 at 1.23.40 AM.png

HTML:

<div ng-if="showWidget == 'requests'">

<div class="container">

<!-- your widget template -->

  <div class="col-md-10 center-div">

  <h3 style="display:inline-block;float:left;">Requests</h3>

  <div ng-repeat="incident in data.requestList | limitTo:5" class="each-incident">

      <h4>{{incident.number}}</h4>

      <p style="margin-bottom:0px;">{{incident.short_desc}}</p>

  </div>  

</div>

</div>

The first line of this html has ng-if. Based on "data" broadcasted with the event, these widgets are shown/hidden.

Client Controller:

function($scope,$rootScope,$timeout) {

  /* widget controller */

  var c = this;

  $scope.showWidget = "";

        //Listening for "showHideWidget" event

  $rootScope.$on('showHideWidget', function(event,data) {

  $timeout(function(){

            $scope.showWidget = data;

  });

  });

}

CSS:

.each-incident{

display:flex;

  justify-content:space-between;

  align-items:center;

  padding:10px;

  border-top:1px solid #ddd;

  clear:both;

}

.center-div{

  float: none;

  margin-left: auto;

  margin-right: auto;

}

Server script:

(function() {

  /* populate the 'data' object */

  /* e.g., data.table = $sp.getValue('table'); */

data.requestList = [];

var gr = new GlideRecord('change_request');

gr.addQuery('category','Hardware');

gr.query();

while(gr.next()){

var temp = {};

  temp.number = gr.number.toString();

  temp.short_desc = gr.short_description.toString();

  data.requestList.push(temp);

}

})();

Step 5: Create Widget 3 (Create request)

Screen Shot 2016-06-26 at 1.43.33 AM.png

HTML:

<div ng-if="showWidget == 'create'" class="col-md-10 center-div">

  <h3 style=" border-bottom: 1px solid #ddd;padding-bottom:5px; ">Create Request</h3>

<form class="form-horizontal">

      <div class="form-group">

              <label for="" class="col-sm-2 control-label">Request Number</label>

              <div class="col-sm-10">

                      <input type="text" class="form-control"   placeholder="Number" autocomplete="off"> </div>

      </div>

      <div class="form-group">

              <label for="" class="col-sm-2 control-label">Short Description</label>

              <div class="col-sm-10">

                      <input type="text" class="form-control"   placeholder="Short Description" autocomplete="off"> </div>

      </div>

    <div class="form-group">

              <label for="" class="col-sm-2 control-label">Description</label>

              <div class="col-sm-10">

                      <textarea class="form-control" rows="3"></textarea>

      </div>

      <div class="form-group">

              <div class="col-sm-offset-2 col-sm-10">

                      <div class="checkbox">

                              <label>

                                      <input type="checkbox"> High priority </label>

                      </div>

              </div>

      </div>

      <div class="form-group">

              <div class="col-sm-offset-2 col-sm-10">

                      <button class="btn btn-default">Submit</button>

              </div>

      </div>

</form>

</div>

Client Controller:

function($scope,$rootScope,$timeout) {

  /* widget controller */

  var c = this;

  $scope.showWidget = "";

  $rootScope.$on('showHideWidget', function(event,data) {

  $timeout(function(){

  $scope.showWidget = data;

  });

  });

}

CSS:

.center-div{

      margin-left: auto;

      margin-right: auto;

  float:none;

}

Step 6: Create Widget 4 (Contact)

Screen Shot 2016-06-26 at 1.48.47 AM.png

HTML:

<div ng-if="showWidget == 'contact'">

      <div class="container">

              <!-- your widget template -->

              <div class="col-md-10 center-div">

                      <h3 style=" border-bottom: 1px solid #ddd;padding-bottom:5px; ">Contact</h3>

                      <div class="flex-display col-md-9">

                              <div class="">

                                      <h4>Address:</h4>

                                  <p class="remove-margin">XYZ Company</p>

                                      <p class="remove-margin">123 Washington st</p>

                                  <p class="remove-margin">Washington</p>

                              </div>

                              <div>

                                      <div class="">

                                              <h4>Email:</h4>

                                              <a href="javascript:void(0)">abc@abc.com</a>

                                      </div>

                                      <div class="">

                                              <h4>phone</h4>

                                              <a href="javascript:void(0)">(123)4567890</a>

                                      </div>

                              </div>

                      </div>

              </div>

      </div>

Client Controller:

function($scope,$rootScope,$timeout) {

  /* widget controller */

  var c = this;

  $scope.showWidget = "";

  $scope.$on('showHideWidget', function(event,data) {

  $timeout(function(){

  $scope.showWidget = data;

  });

  });

}

CSS:

.flex-display{

  display:flex;

  justify-content:space-between;

  padding:10px;

  clear:both;

  margin-left: auto;

  margin-right: auto;

  float: none;

}

.center-div{

  float: none;

  margin-left: auto;

  margin-right: auto;

}

.remove-margin{

margin-bottom:0px;

}

Step 7: Adding our widgets to Service Portal page.

              The last and final step is to add the widgets we created to a Service portal page using Service portal designer.

Screen Shot 2016-06-22 at 4.22.33 PM.png

click on "Service portal configuration" which takes you to a new page with a list of options.

Screen Shot 2016-06-22 at 4.22.47 PM.png

Select designer, A new page opens up and u can see all the "Service portal pages", search for your page, in my case its "sp_examples_homepage"

Screen Shot 2016-06-26 at 1.53.47 AM.png

Now in the page designer view drag and drop "Container" on the page followed by 12 column layout. On the left side, you can see all the widgets available for us to use, search for our widget we created in step 3 (Menu pills) and drag and drop that into the 12 column layout.

Drag and drop another 12 column layout below the "Menu Pills" widget. Search for our widgets we created in step 4,5,6 (All requests, Create request, Contact widget) and drag and drop them onto the 12 column layout. It should look something like this.

Screen Shot 2016-06-26 at 2.01.33 AM.png

We have successfully added our widgets to the page. Now let's check out this widget in action. Click on "portals" under "Service Portal" Application menu. Select the portal we used for this tutorial and hit "try it" button at the bottom.

You should see your Menu pills Widget communicating with other widgets to hide/show them.

widget_comm.gif

This is just a simple demonstration of how widgets can talk to each other. $rootScope.$broadcast('myCustomEvent', 'data'); can be very useful, when you want to send data to other widgets.

Sorry for the long post, hope this helps.

Thanks,

Sush

34 Comments