toni_soueid
ServiceNow Employee
ServiceNow Employee

In this blog post I show how one can control the list of available choices in a ServiceNow form depending on the current choice of a record.

Setting the context


For a practical illustration, we will be controlling the list of available choices of the State field of an incident.
In the out of the box installation of ServiceNow (for example on demo.service-now.com), an Incident can have the following states:

find_real_file.png

We will be controlling the list of choices for the incident state as per the following state diagram:

incidents fsm

As per the diagram, we can only move into the Active state either from the New state or if the incident is just being created.

Step 1: creating a states transition table



In order to make the solution as dynamic as possible we create a new table in ServiceNow named incident_state_matrix having two columns (source_state, destination_state).

This table has two choice fields 'Source State' and 'Destination State' that allow inserting valid transitions. These fields are choice lists that are are based on the incident states from the Incident [incident] table as per the screenshot below.

find_real_file.png

In this table we insert rows that represent the allowed transitions in the above diagram. Below is a screenshot of the populated table:

find_real_file.png

Step 2: Business rule that propagates the allowed states of an incident to the client browser



Create the following business rule:

Name: Allowed Incident States
Table: Incident
When: display
Active: true

In the script section paste the following:



getAllowedStates();

function getAllowedStates() {
var current_state = current.state;
var ismgr = new GlideRecord('u_incident_states_matrix');
ismgr.addQuery('u_source_state', current_state);
ismgr.query();

var allowed_states = [];
var index = 0;

while (ismgr.next()) {
allowed_states[index++] = ismgr.u_destination_state.toString();
}

g_scratchpad.allowed_states = allowed_states;
}


What is the above business rule does is generate an array of allowable states that is sends to the client browser as a scratchpad object.
A client script on the client side will have to process the propagated array and control the list of selectable choices.

Step 3: Create a helper UI Script that facilitates enabling/disabling choice list options



Note: this script is inspired from a post that appeared on the SNCGuru blog at http://www.servicenowguru.com/scripting/client-scripts-scripting/removing-disabling-choice-list-options/

Create the following UI Script:

Name: DisableEnableOptions
Active: true
Global: true
Paste the following script:



function disableAllOptions(fieldName) {
fieldName = g_form.removeCurrentPrefix(fieldName);
var control = g_form.getControl(fieldName);
if (control && !control.options) {
var name = 'sys_select.' + this.tableName + '.' + fieldName;
control = gel(name);
}
if (!control)
return;

if (!control.options)
return;

var options = control.options;
for (var i = 0; i < options.length; i++) {
var option = options<i>;
control.options<i>.disabled = 'true';
}
}

function disableOption(fieldName, choiceValue) {
fieldName = g_form.removeCurrentPrefix(fieldName);
var control = g_form.getControl(fieldName);
if (control &amp;&amp; !control.options) {
var name = 'sys_select.' + this.tableName + '.' + fieldName;
control = gel(name);
}
if (!control)
return;

if (!control.options)
return;

var options = control.options;
for (var i = 0; i < options.length; i++) {
var option = options<i>;
if (option.value == choiceValue) {
control.options<i>.disabled = 'true';
break;
}
}
}

function enableOption(fieldName, choiceValue) {
fieldName = g_form.removeCurrentPrefix(fieldName);
var control = g_form.getControl(fieldName);
if (control &amp;&amp; !control.options) {
var name = 'sys_select.' + this.tableName + '.' + fieldName;
control = gel(name);
}
if (!control)
return;

if (!control.options)
return;

var options = control.options;
for (var i = 0; i < options.length; i++) {
var option = options<i>;
if (option.value == choiceValue) {
control.options<i>.disabled = '';
break;
}
}
}


Step 4: Client script that controls the list of choices



Create the following client script:

Name: Allowed Incident States
Active: true
Global: true
Type: onLoad
Table: Incident

In the script section paste the following:



function onLoad() {
try {
var current_state = g_form.getValue('state');
disableAllOptions('state');
enableOption('state', current_state);
var allowed_states = g_scratchpad.allowed_states;
var nb_states = allowed_states.length;
for (var index = 0; index < nb_states; index++) {
enableOption('state', allowed_states[index]);
}
}
catch (err) {
jslog(err.message);
}
}


Step 5: Business rule that checks if a state is allowed before saving a record



Create the following business rule:

Name: Check If Incident State Allowed
Table: Incident
Active: true
When: before
Insert: true
Update: true

Paste the following script:



checkIfStateAllowed();

function checkIfStateAllowed() {
var bad_state = true;
//If the record is being inserted then previous.state is null
var previous_state = previous.state.toString() == 0 ? 1 : previous.state.toString();
var current_state = current.state.toString();

if (previous_state != current_state) {

var ismgr = new GlideRecord('u_incident_states_matrix');
ismgr.addQuery('u_source_state', previous_state);
ismgr.query();

while (ismgr.next()) {
if (current_state == ismgr.u_destination_state.toString()) {
bad_state = false;
break;
}
}

if (bad_state == true) {
//If current.state did not match any destination state then we have to abort
gs.addErrorMessage('Incident State Not Allowed');
current.setAbortAction(true);
}
}
}


Testing



To test the solution create a new incident as per the below screenshot:

find_real_file.png

On the form you will notice that only the New and Active states are available:

find_real_file.png

If we set the incident state to Active and save the form then the list of available choices changes:

find_real_file.png

I hope this blog post has been useful for you.

Toni Soueid
Technical Consultant
ServiceNow
France

2 Comments