SATURDAY, MAY 19, 2012

Hide Empty Variables on a Standard Form

S

ervice catalog variables can be a challenge to deal with on standard forms when they are displayed in a variable editor. I’ve written before about different ways that you can solve one of these challenges…making the variables read only, so that they can’t be modified after the initial submission through the service catalog interface. Another common problem I’ve seen is that you can end up with a lot of variables that end up empty in the variable editor on your request item or task because they were optional or hidden on the front-end catalog form. If the variables are empty and you aren’t going to have users interact with them on the standard forms then there isn’t much use in having these variables show up at all in the variable editor.

Until now there really hasn’t been a good way to deal with this issue because of the challenges of dealing with so many different variable types in client-side JavaScript. A couple of days ago one of my colleagues, Jacob Kimball, suggested to me that we might be able to overcome this issue by using a ‘display’ business rule to collect the blank variable information at the server and then pass those variable names to the client. So, you can thank Jacob Kimball for the brilliance of this solution. I’m just spreading the love. :)

As explained above, the key to making this work is a ‘display’ business rule. The business rule runs before the display of any record in the table (tasks in this case) and queries the ‘sc_item_option_mtom’ and ‘question_answer’ tables to collect any variable names for empty variables. Then it passes this information in the ‘g_scratchpad’ object to the client to hide the variables on the form.

Here is how you could set up the business rule. The script is designed to hide any empty variables for any task records whether they are generated from a record producer or as a catalog item.

‘Hide Empty Variables’ Business Rule
Name: Hide Empty Variables
Table: Task
When: display
Condition: !RP.isPopup()
Script:

//Initialize the scratchpad variable
g_scratchpad.emptyVars = '';

//Check to see if a variable pool exists
var count = 0;
for(vars in current.variable_pool){
   count++;
   break;
}

//If a variable pool exists then collect empty variable names
if(count > 0){
   var emptyVars = new Array();
   var table = current.getTableName();
   //Query for the empty variables for this record
   //Catalog item and task variables pull from 'sc_item_option_mtom' table
   if(table == 'sc_req_item' || table == 'sc_task'){
      var itemVars = new GlideRecord('sc_item_option_mtom');
      if(table == 'sc_req_item'){
         itemVars.addQuery('request_item', current.sys_id);
      }
      if(table == 'sc_task'){
         itemVars.addQuery('request_item', current.request_item.sys_id);
      }
      itemVars.addNullQuery('sc_item_option.value');
      //Exclude Label and Container variables
      itemVars.addQuery('sc_item_option.item_option_new.type', '!=', 11);
      itemVars.addQuery('sc_item_option.item_option_new.type', '!=', 19);
      itemVars.addQuery('sc_item_option.item_option_new.type', '!=', 20);
      itemVars.query();
      while(itemVars.next()){
         //Add variable names to the emptyVars array
         emptyVars.push(itemVars.sc_item_option.item_option_new.name.toString());
      }
   }
   else{
      //All other variables pulled from 'question_answer' table
      var producerVars = new GlideRecord('question_answer');
      producerVars.addQuery('table_sys_id', current.sys_id);
      producerVars.addNullQuery('value');
      //Exclude Label and Container variables
      producerVars.addQuery('question.type', '!=', 11);
      producerVars.addQuery('question.type', '!=', 19);
      producerVars.addQuery('question.type', '!=', 20);
      producerVars.query();
      while(producerVars.next()){
         //Add variable names to the emptyVars array
         emptyVars.push(producerVars.question.name.toString());
      }
   }

   //Store the result in the scratchpad
   g_scratchpad.emptyVars = emptyVars.join();
}

Once you’ve got the empty variable names collected all you have to do is set up a client script to grab the ‘g_scratchpad’ variable, split out any empty variable names, and hide each one. The client script is pretty simple since the heavy lifting is being done in the business rule. Just make sure that you check the ‘Inherited’ checkbox if you decide to set this up on the task table!

‘Hide Empty Variables’ Client Script
Name: Hide Empty Variables
Type: OnLoad
Table: Task
Inherited: True
Script:

function onLoad() {
   //Hide all empty variables using the scratchpad object passed from 'Hide Empty Variables' business rule
   if(g_scratchpad.emptyVars != ''){
      var emptyVars = g_scratchpad.emptyVars.split(',');
      for(i = 0; i < emptyVars.length; i++){
         eval("g_form.setDisplay('variables." + emptyVars[i] + "', false)");
      }
   }
}

Comments

Posted On
Jun 16, 2011
Posted By
Abhiram Bharadwaj

Brilliant !

Thanks a lot Mark !

Posted On
Jun 16, 2011
Posted By
Steve Darity

That is Very Cool. Just recently learned about ‘Display’ Business Rules. This functionality should be a user configurable property setting in Service Now.

Thank You for the Contribution.

Posted On
Jun 21, 2011
Posted By
Mark

One thing to watch out for are any fields that are still marked as mandatory, if the fields get hidden by the client script, the record may not be able to be modified.

Posted On
Jul 15, 2011
Posted By
Matt Benson

Love this functionality. My users certainly enjoy it.

I would love to be able to extend this sort of functionality to email notifications. Specifically approval requests. Currently all variables show up in those notifications. It would be nice to not include those that are empty.

Posted On
Jul 18, 2011
Posted By
Mark Stanger

This is certainly possible, but it depends on how you are including those variable values in your email. You would have to add or modify a mail script for that notification to check each variable as it gets added to the notification and make sure that it has a value.

Posted On
Jul 18, 2011
Posted By
Matt Benson

We are using the Summary of Requested Items mail script from the wiki.

http://wiki.service-now.com/index.php?title=Scripting_for_Email_Notifications#Summary_of_Requested_Items

Posted On
Jul 27, 2011
Posted By
Mark

This is what we use in our email template which may help with not passing empty variables

   template.print("<b>Summary of Requested Item</b>: \n");  
   template.print("<i>" + gs.getProperty("glide.servlet.uri") + "</i>: \n");  
   var desc = current.sysapproval.short_description;
   var number = current.sysapproval.number;

   template.print("\n");
   template.print("Request Item " + number + ":" + desc + " \n");
   for (key in current.sysapproval.variables) {
            var v = current.sysapproval.variables[key];
            if(v.getGlideObject().getQuestion().getLabel() != '') {
                if(v.getDisplayValue() != 'false'){
                    if(v.getDisplayValue() != ''){
                    if (v != "" &amp;&amp; v != null &amp;&amp; typeof(v) != "undefined") {
                        template.space(4);
                        template.print('' +  v.getGlideObject().getQuestion().getLabel() + ": " + v.getDisplayValue() + " \n");
                        }
                    }
                }  
            }
        }
   template.print("\n");
Posted On
Jul 28, 2011
Posted By
Mark Stanger

Awesome! Great example. For the benefit of others, the ‘if(v.getDisplayValue…’ lines in the middle of the script are the part that filters out the empty variables. Thanks for sharing!

Posted On
Oct 27, 2011
Posted By
rohana

Hi Mark, thanks for sharing this. How to hide those

1. What are 11, 19, 20 meaning in > producerVars.addQuery(‘question.type’, ‘!=’, 19)?
2. How to hide variables that already set to visible = false but has pre-defined value such as ‘No’, ‘None’, ’1′. They are still appearing although the visibility has been set to false during the form-filling process.

appreciate your help on this!

Posted On
Oct 27, 2011
Posted By
Mark Stanger

Thanks. Those numbers correspond to specific variable types (labels and containers) that we don’t want included in the query because they should not be hidden.

Regarding hiding variables with a matching default value, you can modify the script to do this, but I think it will be difficult to determine which items to really hide. You may have some cases where an un-changed default value might actually be useful information. Any ‘visible = false’ setting that you’ve performed in the catalog or variable setup won’t transfer well to the back-end forms…which is why the script is necessary.

If you want to try hiding variables whose default values have not been changed, then you can modify the script like this…
…For the ‘itemVars’ while loop…

//Exclude any variables whose value matches their default value
if(itemVars.sc_item_option.item_option_new.default_value != itemVars.sc_item_option.value){
   //Add variable names to the emptyVars array
   emptyVars.push(itemVars.sc_item_option.item_option_new.name.toString());
}

…And within the ‘producerVars’ while loop…

]
//Exclude any variables whose value matches their default value
if(producerVars.question.default_value != producerVars.value){
   //Add variable names to the emptyVars array
   emptyVars.push(producerVars.question.name.toString());
}
Posted On
Dec 08, 2011
Posted By
Josh B

I’ve modified this a bit to hide variables, labels, containers and UI pages that are not set to Global. However, it doesn’t seem to work with containers that are set to be “two columns wide”. Works find for one column layouts. I’ve confirmed that it’s not the business rule. Seems to be something with the setDisplay function. Here’s the modified version of the script, if anyone is interested:

//Initialize the scratchpad variable
g_scratchpad.emptyVars = '';

//Check to see if a variable pool exists
var count = 0;
for(vars in current.variable_pool){
count++;
break;
}

//If a variable pool exists then collect empty variable names
if(count > 0){
var emptyVars = new Array();
var table = current.getTableName();
//Query for the empty variables for this record
//Catalog item and task variables pull from 'sc_item_option_mtom' table
if(table == 'sc_req_item' || table == 'sc_task'){
var itemVars = new GlideRecord('sc_item_option_mtom');
itemVars.addQuery('request_item', (table == 'sc_req_item' ? current.sys_id : current.request_item.sys_id));
var q1 = itemVars.addNullQuery('sc_item_option.value');
//Include variables not defined as global
q1.addOrCondition('sc_item_option.item_option_new.global', 'false');
itemVars.addQuery('sc_item_option.item_option_new.type', '!=', 11);
itemVars.addQuery('sc_item_option.item_option_new.type', '!=', 15);
itemVars.addQuery('sc_item_option.item_option_new.type', '!=', 19);
itemVars.addQuery('sc_item_option.item_option_new.type', '!=', 20);
itemVars.query();

while(itemVars.next()){
//Add variable names to the emptyVars array
emptyVars.push(itemVars.sc_item_option.item_option_new.name.toString());
}

//This is for checkboxes
itemVars = new GlideRecord('sc_item_option_mtom');
itemVars.addQuery('request_item', (table == 'sc_req_item' ? current.sys_id : current.request_item.sys_id));
itemVars.addQuery('sc_item_option.item_option_new.type', 7);
itemVars.addQuery('sc_item_option.value', 'false');
itemVars.query();
while(itemVars.next()){
//Add variable names to the emptyVars array
emptyVars.push(itemVars.sc_item_option.item_option_new.name.toString());
}

//This is for labels, containers and UI pages
itemVars = new GlideRecord('sc_item_option_mtom');
itemVars.addQuery('request_item', (table == 'sc_req_item' ? current.sys_id : current.request_item.sys_id));
itemVars.addQuery('sc_item_option.item_option_new.type','IN','11,15,19,20');
itemVars.addQuery('sc_item_option.item_option_new.global', 'false');
itemVars.query();
while(itemVars.next()){
//Add variable names to the emptyVars array
emptyVars.push(itemVars.sc_item_option.item_option_new.name.toString());
}
}else{
//All other variables pulled from 'question_answer' table
var producerVars = new GlideRecord('question_answer');
producerVars.addQuery('table_sys_id', current.sys_id);
producerVars.addNullQuery('value');
//Exclude Label and Container variables
producerVars.addQuery('question.type', '!=', 11);
producerVars.addQuery('question.type', '!=', 19);
producerVars.addQuery('question.type', '!=', 20);
producerVars.query();
while(producerVars.next()){
//Add variable names to the emptyVars array
emptyVars.push(producerVars.question.name.toString());
}
}

//Store the result in the scratchpad
g_scratchpad.emptyVars = emptyVars.join();
}
Posted On
Dec 08, 2011
Posted By
Mark Stanger

Thanks Josh!

Posted On
Dec 12, 2011
Posted By
Paul

Mark,

I have a need to edit some variables at certain stages of the workflow once the item is created.
I am trying to modify this script to allow enabling and disabling mandatory for the variables based on another flag set on the sc_task record. I modified the push line to check for mandatory attribute but the reference doesn’t hold up. Any advice?

      while(itemVars.next()){
      if(itemVars.sc_item_option.sc_cat_item_option.mandatory=='true') {
         mandatoryVars.push(itemVars.sc_item_option.item_option_new.name.toString());
      }
Posted On
Dec 12, 2011
Posted By
Mark Stanger

Hey Paul,

I think the problem is in your ‘if’ statement. If you walk through that reference, you’ll notice that ‘sc_cat_item_option’ is empty. I think if you replace that with ‘item_option_new’ then it will work better.

Posted On
Dec 14, 2011
Posted By
Paul

Thanks Mark,

I found that just about the same time I saw your post. My next question… How can I make this work for Record Producers?

It appears that sc_item_option_mtom only works for sc_req_item. Can you point me in the right direction?

Posted On
Dec 14, 2011
Posted By
Mark Stanger

That’s handled in the ‘else’ statement in the business rule script above. Record producer variables are stored in the ‘question_answer’ table.

Posted On
May 11, 2012
Posted By
Wendy H

Has anyone had any issues with this with the Aspen Hotfixes? We applied the Hotfixes on QA to 04_25_2012_1204 last week and ever since we applied the patch I can no longer run the BR – It hangs all browsers and says due to long running script that the page won’t load. Is there a fix for this?

Posted On
May 12, 2012
Posted By
Mark Stanger

I haven’t seen or heard of this issue. The only thing I can suggest would be to confirm which part of the business rule is causing the problem by taking pieces out and replacing them with ‘gs.log’ entries until you identify the issue. If you’re going to K12 I could take a look at it in person.

Leave a Reply


Notify me of followup comments via e-mail. You can also subscribe without commenting.

Latest Comments

  • Jim Coyne: I’m not sure exactly what you are looking for, but can you use “window.location” in your...
  • Ian: Might want to check the single quotes around ITIL in the condition line, they gave an error for me until I...
  • Mark Stanger: That’s correct. This returns instance URLs. I don’t have an equivalent currently that...
  • ND: Hi Mark, This is very useful information. I am looking for similar method to find URL of a site created by us. We...