Client Script for multiple fields

General Add comments
by:


Imagine you have a form – say for example the incident form.

And the impact is depended on the selected values from the “Urgency” and the “Category” field.
For example we define these rules for the fields on the form

Urgency Category Impact
1-High Database 1-High
2-Medium Software 2-Medium
3-Low Hardware 3-Low
3-Low




To get the rules working for the incident form, we create the following Client Script:
Name: Client Script “OnChange” for Urgency

function onChange(control, oldValue, newValue, isLoading, isTemplate) {
   if (isLoading || newValue == '') {
      return;
   }

   // Create variable for the Impact field and set it on default 3-Low
   var impact = "3";
   // Get value from Category field
   var category = g_form.getValue("category");
   if(newValue == "1" && category == "database") {
      impact = "1";
   } else if(newValue == "2" && category == "software") {
      impact = "2";
   } else if(newValue == "3" && category == "hardware") {
      impact = "3";
   }
 
   // Set impact value on Impact field
   g_form.setValue("impact", impact);
}

This Client Script will work correctly, but only when we set the Category field before setting the Urgency field.
For example I will choose Category “Software” and choose “2-Medium” on the Urgency field.
The impact will be set on 2-Medium according to our rules (see above).

But when we use another order it can go wrong.
For example I will choose the Urgency “1-High” and then Category “Database” the impact must be “1-High” but will not change and stays on his own value.

When you are working a bit longer with ServiceNow you will know that this can be fixed by a second Client Script for the Category field:
Name: Client Script “OnChange” for Category

function onChange(control, oldValue, newValue, isLoading, isTemplate) {
   if (isLoading || newValue == '') {
      return;
   }

   // Create variable for the Impact field and set it on default 3-Low
   var impact = "3";
   // Get value from Urgency field
   var urgency = g_form.getValue("urgency");
   if(newValue == "database" && urgency == "1") {
      impact = "1";
   } else if(newValue == "software" && urgency == "2") {
      impact = "2";
   } else if(newValue == "hardware" && urgency == "3") {
      impact = "3";
   }
 
   // Set impact value on Impact field
   g_form.setValue("impact", impact);
}

And it will work…

But wait!

There is an alternative for this and I think it’s better and gives you a better overview of the working.
It will also be easier to maintain.

Instead of creating an OnChange Client script for each field, we will create one “onLoad” Client Script:
Name: Client Script “onLoad”

function onLoad() {
   //Type appropriate comment here, and begin script below
   try {
      // Urgency
      var urgency_field = g_form.getControl('urgency');
      urgency_field.onchange = setImpact;
   } catch (err) { }
   try {
      // Category
      var category_field = g_form.getControl('category');
      category_field.onchange = setImpact;
   } catch (err) { }
}

function setImpact() {
   // Get the urgency and Category values
   var urgency = g_form.getValue("urgency");
   var category = g_form.getValue("category");

   // Create variable for the Impact field and set it on default 3-Low
   var impact = "3";

   if(category == "database" && urgency == "1") {
      impact = "1";
   } else if(category == "software" && urgency == "2") {
      impact = "2";
   } else if(category == "hardware" && urgency == "3") {
      impact = "3";
   }

   // Set impact value on Impact field
   g_form.setValue("impact", impact);

   onChange(this.name);
}

So what does this code do?


In the onLoad function we will set a function called “setImpact” on the onchange event for the two fields (Urgency and Category).
I have put these in a try catch for the times the fields are not available in the DOM (read Form) the javascript will continue instead of crashing 😉

So when our category or urgency changes, we will apply our rules and set the correct Impact value no matter in which order the fields are set.
The first time I created this code I had some problems with the normal onChange Client Scripts from the selected fields.
The onChange scripts were not executed any more, because I override the onchange event of the control.
At the last line of the onchange function I execute the ServiceNow onChange function, so the normal onChange script will execute.

I hope you like this article, for any questions please contact me at menno.aret@2e2.nl

4 Responses to “Client Script for multiple fields”

  1. SimonMorris Says:

    Nice post – I’d also say there is benefit in abstracting all of this logic into a single backend script though.

    It’s easy to see how you derive the priority when various client scripts are laid out in a blog post like this, but if you work in a large team it might be confusing to have logic distributed over multiple scripts.

    You could do something nice by holding all of the logic in a single script include and then use Client Script to retrieve results over GlideAjax. Small performance hit, big code maintainability advantage.

    Even better – hold the mapping of categories and urgency levels in a ServiceNow table and make it data driven.

  2. Brajendra Says:

    Thanks.. We did this using ui script which was loading on every reload. This will save the load time for pages.

  3. David Says:

    This functionality is great but after Geneva this does not work anymore, do you have any idea on how to adapt this script to work on Geneva?

  4. Alvin Says:

    David, i know this is little bit late, but for Helsinki you can use variableOnChange(this.name) to trigger the original onChange script.

Leave a Reply