alan_lowrance
Mega Guru

For those of you working with Category + Subcategory fields, you know how much of a pain it was to initially set them up.   Your Category choices are defined in the sys_choice table by table, element ("category"), value... and then you create other entries for table, element ("u_subcategory"), value, dependent value.   Then you relate which thing it's looking to for that dependent value on the dictionary entry for the subcategory item.

Anyways, once you have a Category + Subcategory, if you want those to show up and actually filter the Subcategory down dynamically on a Record Producer, you'll need to use AJAX in client scripts to make server calls since a Record Producer usually only submits info to the server upon submission.

The category variable on the Record Producer should work fine without any tweaking cause it's looking at the correct table & element in the choice list table.   The problem arises when you look at the subcategory and it shows ALL choices because it doesn't dynamically query the choices against the dependent value.

Stay with me, so you can make a reference qualifier on the Subcategory variable to limit the choices based on a dependency... but since the record producer isn't a real "living record" yet you have to force it to update.   Once the variables are attached to a real record, this reference qualifier should work normally so your client script isn't going to need to run on Requested Items or Catalog Tasks or anything... just in the Catalog Item View.

The Subcategory variable (lookup select box) should be looking at the sys_choice table and have a reference qualifier similar to:

javascript:'name=incident^element=u_subcategory^dependent_value=' + current.variables.category

Then an onChange client script that runs whenever category is changed will feed variables to a script include and you might want to use this same script include for multiple tables so lets make the script include first:

var DenburyAjax = Class.create();

DenburyAjax.prototype = Object.extendsObject(AbstractAjaxProcessor, {

    getSubcategories: function() {

      var table = this.getParameter('sysparm_table');

      var element = this.getParameter('sysparm_element');

      var category = this.getParameter('sysparm_category');

   

      var choice = new GlideRecord('sys_choice');

      choice.addQuery('name',table);

      choice.addQuery('element',element);

      choice.addQuery('dependent_value',category);

      choice.orderBy('sequence');

      choice.query();

    while(choice.next()) {

        if (!choice.inactive) {

                  var item = this.newItem("item");

                        item.setAttribute('label', choice.label);

                        item.setAttribute('value', choice.value);

        }

    }

}

   

});

Make sure you check the "Client Callable" box.

Now to feed the category value to that and build the choices on subcategory, your catalog client script should run onChange of the category variable and only the Catalog Item View:

function onChange(control, oldValue, newValue, isLoading) {

  if ((isLoading) || (newValue == ''))

  return;

  var aj = new GlideAjax("DenburyAjax");

  aj.addParam("sysparm_name", "getSubcategories");

  aj.addParam("sysparm_table", "incident");

  aj.addParam("sysparm_element","u_subcategory");

  aj.addParam("sysparm_category", newValue);

  aj.getXML(getResponse);

}

function getResponse(response) {

  var items = response.responseXML.getElementsByTagName("item");

  g_form.clearOptions('u_subcategory'); //has to clear previous buildout  

  g_form.addOption('u_subcategory','','-- None --');

  for (var i = 0; i < items.length; i++) {

    var item = items[i];

    var value = item.getAttribute("value");

    var label = item.getAttribute("label");

    g_form.addOption('u_subcategory', value, label);

  }

}

Make sense? Any questions?

Comments
Kilo Guru

are we saying the category / subcategory dependency is only an issue in record producers?



I'm having a few dramas and think it's probably AJAX related (I'm not using it !)



but generally the cstegory/subcategory work fine when   creating a record in application.  



my issues have been when trying to filter on list collectors based on values in the other record producer variables . does this apply in a similar way ?


Mega Guru

The category/subcategory dependency should work fine outside of record producers because when you're looking at forms or records, those dependencies update the choices automatically.   I think "Choice" variables are smarter than the "Select Boxes" & "Lookup Select Boxes" in that way.



For list collectors, they work much like a "Reference" variable and reference qualifiers do update dynamically with the server whenever things change so you probably just need a good reference qualifier that uses the current value from another field.   For example if you want to have a list of people only at a certain location, you can make the List Collector point to sys_user and the reference qualifier be javascript: 'location= ' + current.caller_id.location   or whatever field has the value you want to dynamically filter off of.



If you're in a record producer and want to filter based on another variable, then yes you might have to do an AJAX thing similar to above (if reference qualifier alone doesn't work).


ServiceNow Employee
ServiceNow Employee

No need for the scripts.   Just add this to the attribute field of your subcategory variable:   ref_qual_elements=category   (or whatever you've named your category variable).


That does the refresh of your subcategory lookup select box when category changes.


Mega Guru

Ben, I don't see it using the reference qualifier or refreshing when I use a Lookup Select Box:


I have the dependencies already created on the sys_choice table so I'm having it look there and then reference qual: dependent_value=catalogvariablename


And its not working with or without attribute: ref_qual_elements=catalogvariablename


ServiceNow Employee
ServiceNow Employee

Here's an example... Using variables 'category' and 'subcategory' that are pointing to the sys_choice.


category variable:  


reference qualifier:   name=incident^element=category^language=en^inactive=false



subcategory variable:  


reference qualifier: javascript:'name=incident^element=subcategory^language=en^inactive=false^dependent_value=' + current.variables.category


attribute: ref_qual_elements=category



Give that a shot.


Mega Guru

Wow, that worked! I thought you couldn't use "current.variables" on a catalog/record producer because it's not in the database yet… usually you have to use g_form when working on forms that don't have anything written to DB yet


Kilo Contributor

Benn23,


Thanks for this unique approach. I've been struggling with category/subcategories for quite a while, tried dozens of variations in scripts but none gave the desired result. Those two lines in the reference qualifier & attribute saved my life (and the project besides).



The only 'weird' behavior I experience (Helsinki on any browser) is whenever I select another category, an additional --None-- is added to my subcategory list. But that's a minor detail: the end user just has to select the correct category straight away and don't complain about those multiple --None--s .



What I realy like to know, for now the language = static (en), but I would like to make it dynamic (user dependent) too. Currently we have EN / NL / FR translations for the labels of the subcategories and DE / ES / IT translations are being created. Is it possible to incorporate a second dynamic variable for example language='+gs.getSession().getLanguage() in this two line approach? I've tried something like



javascript:'name=incident^element=subcategory^inactive=false^dependent_value=' + current.variables.category + language='+gs.getSession().getLanguage()



but that did not work. If you (or someone else) has any suggestion, it would be much appreciated.


ServiceNow Employee
ServiceNow Employee

I'm on an Istanbul instance and the following does work when I switch around my language:


javascript:'name=incident^element=subcategory^language=' + gs.getSession().getLanguage() + '^inactive=false^dependent_value=' + current.variables.category



Have you tried logging out and back in after you change your language?


Kilo Contributor

It works! Looks like the trick is the additional '^ between the 2 parameters. Never thought about that.


Mega Guru

Thank you for sharing, super helpful for my development today.


Mega Guru

benn23 or huwaldsmeets - The none issue that keep on adding none to sub category when category changes. I am facing the same issue. Do you know if its a bug in SN or did you find a workaround? I am Helsinki version.


Kilo Contributor

Hi Jaskaran,


Back then (end of March) I did find a post somewhere suggesting it was a bug, but in our current version (helsinki-03-16-2016__patch9-hotfix0a) I can't reproduce the issue anymore. Might also have to do with my field type: I switched using a Reference field instead of a Lookup Select Box. It gives the same functionality, but instead of 'None' the field is 'blank' in the service portal what kind of looks nicer in my opinion.


Mega Guru

Thanks Huwald! Yeah, seems to be known error and HI request raised already for the issue! I have too now moved from lookup selectbox to reference field! Thanks a million for your reply.