fschuster
ServiceNow Employee
ServiceNow Employee

Let's talk a bit more about Widget options! b-rad already published a great article about the usage of options, which I always like to compare to System Properties. Those can hold values to design content a bit more dynamic, rather than hard-coding values.

The available option types, as of today, are:

  • Integer
  • String
  • Boolean
  • Choice
  • Field name & Field List (both dependent on the "table" option on the according Widget instance)
  • Reference

Within this post we want to look a bit more into the Reference option type.

Use Case #1 - Understanding the Reference option

Before we start with advanced options, let's just have a look what you could do with a standard reference type option. Assume we would want to build a Menu block based off the Instance with Menu [sp_instance_menu] table. Instead of writing a Widget for each and every Menu block, how about we just "optionize" (yes, I think that should be a word moving forward in the Service Portal context ) in a way, that an SP Admin can simply pick the Menu from a reference field, rather than changing the sys_id in the Widget?

Here's what we could do (no need to rebuild this yourself, it's more about how to use the reference option - you will build a widget later on):

  1. Let's assume we'll create a widget called "Menu Block"
  2. Then we will create a reference option in the widget pointing to the Instance [sp_instance_menu] table
  3. Have the Server Script utilize the newly created option value to retrieve the menu record, which will be defined in the widget instance. Retrieve the basic values of that menu with the $sp server-side API and have the HTML display the values within the data object
  4. Create a new Menu record (for demo purposes I added an Image field to the sp_instance_menu table, that we'll pull into the Widget)
  5. Create a widget instance by dragging & dropping the widget onto a page & define a menu
  6. Modify the Menu of an existing widget instance by Ctrl + right-clicking on the widget instance (this does not work in the Designer, you'd have to be on the actual page)
  7. Voila, we changed the instance of that menu block to a different menu.

output_9zFFN7.gif

This example is not meant to be particularly pretty, it should more explain the concept of how to effectively utilize reference options.

I also refrained from providing the code to evaluate the child items for this very reason.

So far so good - now that we know how to use Reference options, let's move on to the advanced use-case.

Probably almost everybody of you has used Reference Qualifiers in the platform view/backend (you name it), to filter down the results of a reference field - e.g. just return all operational CI's on a configuration item reference field or just display active callers on a user reference field.

Now, how would we apply those to a service portal option? The bad news: not at all. The option schema does not accept reference qualifiers. The good news: you can create your own "Option tables". You might have come across the Data Table field, which is defined on the Widget record itself. Per default you will mostly find Instance [sp_instance], but you'll also find e.g. Instance of Simple List [sp_instance_vlist], which is used by the Simple List Widget. All fields on the table defined as the data table, are available options for the widget that uses this table .

Report1.png

In addition, you will still be able to define options via the Widget Options. Be aware that those are not automatically fields on the according instance table, those will be transformed into options represented in the JSON format - here is an example how this would look like based on the first use-case described in this post.

JSONOptions.png

This is great for multiple reasons:

  1. As this is a "real" field, no JSON option, we can apply Reference Qualifiers!
  2. Looks like a form doesn't it? Well, it is! That also means that we can leverage UI Policies to conditionally hide & show options. Sweet! Something else, that we would not be able to achieve, if we would stick to the default Option Schema.

Use-Case #2 - Creating your own Instance Table to apply Reference Qualifiers & leverage UI Policies

Enough talk, let's create a custom "options" table.

  1. Navigate to System Definition > Tables, click Create New
  2. Pick a Name & Label for your new table, given the naming convention of all existing tables I'd suggest something along those lines: "Instance of xyz" / "Instance with xyz". Personally I always went for SP <Name of the Widget> Instance so far.
  3. Extend the new table from Instance [sp_instance]
  4. If you want create a new Module for it within the Service Portal application. Make sure to disable the role creation, numbering etc. - we don't really need this in the context of options.
  5. Click Submit
  6. The table will inherit all fields from the Instance table, so make sure you do not create duplicate fields for something that's already there (e.g. HREF/URL, Bootstrap Color etc.).
  7. Now you can go ahead and create whatever field you want from the Tables view, via the Form Designer or Form Layout - I created the following fields for the demo:
    1. Reference - to Business Services [cmdb_ci_service]
    2. Override Styles - Boolean
    3. Font Color - Color
    4. Border Color - Color

Report3.png

If you navigate to the form of that table, you will most likely see the following (unless you directly created and formatted the form via Form Designer / Layout).

Report4.png

At this point we can start applying our UI Policies and the Reference Qualifier on the Reference field. Let's start with the UI Policy, which should hide the color fields if Override Styles is not checked.

Report5.png

For the reference qualifiers you can Right-click on the label of the reference field and then choose Configure Dictionary.

If you switch into the Advanced View of the dictionary record you will also be able to define an Advanced Reference Qualifier (e.g. calling your own filter function defined in a Script Include), rather than only a Simple Reference Qualifier.

output_L1AD2u.gif

At this point we have prepared our option/instance table: once you've done this, you will be able to choose from the fields on that table right below Data Table, by using the Fields field list.

The Option Schema will not automatically expose all fields as options - quite the contrary: it will only use the fields that you pick within that field list and expose them as options in the widget instance. Another thing that I found is, that the field will have to be on the Widget Instance form - only selecting it within the Fields won't work.

Let's create a new widget to test our new instance table. Open the Widget editor via Service Portal > Service Portal Configuration or https://yourInstance.service-now.com/sp_config

Give your new widget a name, e.g. "Widget Option Test" - if you create a Test Page, be aware that you will have to delete the widget instance on the page and re-add the widget after you changed the Data Table, otherwise it will still point to Instance, rather than to your new table.

Once the widget is created navigate to the platform view/backend and open up the widget.

Report9.png

Scroll down to Data Table & Fields and define your new option table. Also select the fields (and essentially now options) we created.

output_cJFAyE.gif

Now we are almost done - but at this point we have a blank widget, that wouldn't display anything, so let's just add some HTML and data based on the selected service.

Again, this widget will not really make a whole lot of sense, but should rather convey what you will be able to do.

Go back to the Widget Editor. If you had your Widget Editor open when you associated the new data table with your widget record, make sure to reload the widget editor so that it has the correct context, i.e. the new data table.

Write the following code into the Server Script:

function() {

  //initialize serviceValues object within the data object

  data.serviceValues = {};

  //Business Criticality has indeed only one "s" in the tech field name, no error.

  var fields = "name, owned_by, busines_criticality, version, used_for, location";

  //the option name is going to be the technical field name on the table

  var service = options.u_business_service;

  var grService = new GlideRecord("cmdb_ci_service");

  if(grService.get(service)) {

            data.serviceValues = $sp.getFieldsObject(grService, fields);

  }

})();

If you are curious what $sp.getFieldsObject() does, I suggest doing a Ctrl + Right-click on the Widget instance and then do a Log to Console: $scope.data.

Open the developer tools of your browser, go to Console and review the serviceValues object, which will contain e.g. the display values and labels of all the fields we defined.

Debug.png

Note: you can also use $sp.log(), which only outputs if the user has the sp_admin role or is impersonating. You can even use console.log() in the server script to debug objects, variables etc. If you are debugging an object make sure not to prefix it with a string (i.e. console.log("This is my serviceValue object: " + data.serviceValues)), since that would convert it into a string and you would not be able to move through the hierarchy within the console.

Now, we write the following HTML:

<div>

  <div class="panel panel-default">

      <div class="panel-heading" ng-style="{'background-color': options.u_border_color}">

          <h3 class="panel-title">{{data.serviceValues.name.display_value}}</h3>

      </div>

      <div>

          <dl>

              <!-- Because the <dt> tag closes we have to extend the ng-repeat range by using ng-repeat-start, otherwise the <dd> tag could not access the values -->

              <dt ng-repeat-start="item in data.serviceValues" ng-style="{'color': options.u_font_color}">{{item.label}}</dt>

              <dd ng-repeat-end>{{item.display_value}}</dd>

          </dl>

      </div>

  </div>

</div>

Save your Widget and go to Service Portal > Service Portal Configuration and open up the Designer or the platform view of the Widget Instance.

Navigate to your test page and modify the Widget Instance Options by providing a title to the widget, picking a service and providing a font color via the color picker (another great side effect of using real fields instead of JSON options) + a border color, that we'll use for the panel heading (slight misusage of the name, but you get the idea ). We are not using it within the widget, but it's always good to have a title if you go to the list of widget instances - helps distinguishing between instances based of the same widget.

Report12.png

Go to your test page and reload it. It should now look like this, most likely it would contain different data dependent on the service that you chose:

Report13.png

At this point you have successfully created a new Widget Instance table, added fields to be used as options on that particular table and you made use of them within the Widget. I hope you found this article useful and that it will help you to create more dynamic widgets in the future.

3 Comments