Category Archives: Pattern

Custom Element Pattern

Once a week I will try and publish some of my Patterns.  These will be reusable templates for everything from building apps to creating widgets.  This first week I am going to cover custom elements in forms using Formatters.  Be sure to check back weekly for new patterns.

Many times customers want custom functionality that goes beyond the standard form.  A UI Page is good but it requires the user to leave the form or have the content displayed in a pop-up.  Neither of these options are particularly appealing but there is another method which is not widely used, Formatters.

While this is a fairly common term thrown around I see few people actually using this method so here I will provide an overview (with code  of course) on how to implement various styles of custom formatters.

First a quick review of the process.  Start by creating a UI Macro, then navigate to the Formatters list and add a new one.  Each Formatter can link one UI Macro to one table.  You can create new Formatters if you want to link your macro to multiple tables.

The Name of the Formatter can be a friendly name of your new element.  The Table will be the target table to add the functionality to.  The Formatter is your actual UI Macro name with .xml appended to the end.  Since it is a “file name” your UI Macro should not contain spaces, it’s best practice to use an underscore in place of spaces.

Let’s start off easy with just a simple Formatter, adding an image to a form.

  1. Create a new UI Macro: my_image
  2. Add this to the body of the Macro between the Jelly tags
    <img src="http://replygif.net/i/1403.gif" />
  3. Create a new Formatter
    Name: My Image
    Table: Incident
    Formatter: my_image.xml
  4. Navigate to the Incident form and Personalize Form
  5. Add the My Image formatter to the form
    Formatters are usually located after the Fields in the List

If everything worked out you should have an image on your form.  This is not really a pattern yet but is still the basic way to get static information on a form.

Note: If you ever change the Formatter record (not the underlying UI Macro) you need to re-add it to the form.  

Now that we have gone through creating a basic Formatter let’s add some real functionality to it.  There are three patterns I’d like to walkthrough here: first is a custom Formatter that writes to a field and the second is a dynamic Formatter that displays a list and third is a completely client side Formatter.

Custom Field
This pattern creates a formatter that acts like a standard ServiceNow field, reading and writing to a field like normal.

  1. Create a new String field on a form ( I am using Incident for my examples).  The field should have a length of 100
  2. Once the field is added you want to make sure it is NOT displayed on the form since it would conflict with our Formatter
  3. Create a new UI Macro and add this to the body of the macro between the Jelly tags
    <table cellspacing="2" width="100%">
    <tbody>
    <tr>
    <td id="label.incident.u_custom" title="" data-type="label" choice="0" nowrap="true" class="label label_spacing" type="color">
    <span id="status.incident.u_custom" class="label_description" title="" mandatory="false" oclass="">$[SP]</span>
    <label for="u_custom" onclick="return labelClicked(this);" >Custom Element:</label>
    </td>
    <td>
    <input id="incident.u_custom" type="color" onchange="onChange('incident.u_custom');" name="incident.u_custom" value="$[current.u_custom]" autocomplete="off" />
    </td>
    </tr>
    </tbody>
    </table>
  4. Replace u_custom with the name of your new field and incident with whichever form you are working on.
  5. Create a Formatter, Personalize your form and add the new Formatter

You now should have a custom Color Picker element that acts like a ServiceNow field.

Custom Dynamic List
This pattern demonstrates creating a custom list view based on the current record.

  1. Create a New UI Macro and add this as the body of the Macro between the Jelly Tags
    <g2:evaluate>var sys_id = RP.getParameterValue('sys_id').toString();
    var auditRec = new GlideRecord('sys_audit');
    auditRec.addQuery('tablename', 'incident' );
    auditRec.addQuery('documentkey', sys_id );
    auditRec.query();
    var canViewAudit = gs.getSession().getRoles().toString().indexOf("admin") != -1;
    var row_class = "list_odd";
    </g2:evaluate><br/>
    
    <j2:if test="$[canViewAudit]">
    <table style="width:50%">
    <thead>
    <tr class="header">
    <td class="column_head">User</td>
    <td class="column_head">Date</td>
    <td class="column_head">Field</td>
    <td class="column_head">Previous Value</td>
    </tr>
    </thead>
    
    <j2:while test="$[auditRec.next()]">
    <tr class="list_row $[row_class]">
    <td>$[auditRec.user.toString()]</td>
    <td>$[auditRec.sys_created_on.getDisplayValue()]</td>
    <td>$[auditRec.fieldname.toString()]</td>
    <td>$[auditRec.oldvalue.toString()]</td>
    </tr>
    
    <g2:evaluate>
    if( row_class == "list_odd" ){
    row_class = "list_even";
    } else {
    row_class = "list_odd";
    }
    </g2:evaluate>
    </j2:while>
    </table>
    </j2:if>
    <j2:if test="$[canViewAudit==false]">
    <p>$[SP]Audit View is Only viewable by Administrators</p>
    </j2:if>
    
  2. If you are using a form other than incident change it in the script
    This could be generalized to just grab the table name and be applicable to any table
  3. Create the Formatter and add it to the form.

You should now have an Audit list that will display for Admins.   If nothing is showing up make sure auditing is turned on for the table and a change is made.

Client Side Element
This pattern is the most “wide open” in terms of what can be done.  In this example I will recreate the Short Description field but dynamically.  One key thing to keep in mind is the “dynamic” part here refers to performing some AJAX operation.  These calls should always be asynchronous and not block the User.

  1. Create a new UI Macro and add this to the Macro body between the Jelly tags
    <table cellspacing="2" width="100%">
    <tbody>
    <tr>
    <td choice="0" nowrap="true" class="label label_spacing" type="color">
    <label for="dynamic_custom">Short Description:</label>
    </td>
    <td>
    <input id="dynamic_custom" type="text"/>
    </td>
    </tr>
    </tbody>
    </table>
    <script src="https://code.jquery.com/jquery-2.1.1.min.js" />
    <script>
    jQuery.noConflict();(function($){var sys_id = gel('sys_uniqueValue').value;
    
    getDynamicValue();
    
    function getDynamicValue(){
    var incidentRec = new GlideRecord('incident');
    incidentRec.addQuery('sys_id', sys_id);
    
    incidentRec.query( function( incidentRec ){
    if( incidentRec.next() ){
    $("#dynamic_custom").val( incidentRec.short_description.toUpperCase() );
    }
    })
    
    }
    
    })(jQuery)
    </script>
  2. Change references to incident to whichever table you are using
  3. Create the Formatter and add it to the form

When the form loads it will dynamically fetch the Short Description and fill it in.  Keep in mind this is read only, but you could combine this pattern with the others to create that link.

Obviously in practice you will want to do more than get the Short Description and you really are not limited.  You may load in your UI Macro any JavaScript library so I have used this same method combined with DataTables, Handlebars, AngularJS and many more libraries to create rich functionality.

You may also use this technique to load data via Web Service dynamically, creating the effect of having all data from external systems within a ServiceNow form without needing to store it.

Almost every custom element derives from these patterns, if I come up with more I will be sure to share and am interested in seeing what everyone else comes up with!