Creating conditional drop-down lists using JavaScript widgets

November 2014 update: You can also use the Conditional Fields app, an Enterprise-only app that lets you hide and show fields in your tickets to give agents and end-users a better user experience. See Using the Conditional Fields app (Enterprise).

Many Zendesk customers have requested a way for custom drop-down lists to be able to show and hide elements based on certain conditions. Although not currently provided as a custom field type in Zendesk, you can create conditional drop-down lists yourself by creating a JavaScript widget.

The idea is simple but complex in implementation. Each layer adds to complexity so we recommend that you create no more than three layers. For example:

1. parent 1
  a. child 1
    i. sub child 1
  b. child 2        
    i. sub child 2
2. parent 2
  a. child 3       
    i. sub child 3
      a. child 4
      sub child 4

There are two ways of doing conditional fields. The first is if you have no required child fields, the second is if you do. The JavaScript code for each is described below.

For either option, you first need to create a custom drop-down field and then create a JavaScript widget, which controls the behavior (enables the conditional fields) when the field is used in your help desk.

Option 1: No required child fields

The first option is to show and hide the entire child field based on a selection in the parent field. Using this method, the child fields can only be optional, not required.

To build out the JavaScript code for this, you need the custom field ID of each field you want to hide. You can find your custom drop-down list ID here:

conditional_fields1.png

Here's the JavaScript code to create a conditional drop-down list with no required child fields. You can also find the code on github.

(function () {

/* This widget uses arrays to store the fields you which to show or hide based on a users selection
** Each field you wish to hide contains three fields that need to be hidden 
** 1) The title which is a H3 HTML tag. This uses jQuery to search for the title so make one entry in the array like this h3:contains(Division)
** 2) THe description (which is optional) that is a <P> HTML Tag. Like the title we do a searh for words in the description like this p:contains(Which Division) so add that to the next element in the array
** 3) The last bit that need to be in the array is the selector for the field which is like  #ticket_fields_20389132 the number being the ID of the custom field. 
**
** You need to create a array for each condition you wish to exist. aaa
*/

var creativeRequest = ['h3:contains(dental)', 'label:contains(dental)', '#ticket_fields_109934'];

var projectRequest = ['h3:contains(type2)', 'label:contains(type2)', '#ticket_fields_20111097'];


//the array the hides everything
var hideAll = [].concat(creativeRequest, projectRequest);

//condition fields for the end user request form make sure you change the field ID to yours. 
  $j(document).ready(function() {  
	//this builds a map based on the selection of the dropdown field values 
	moodFieldMap = {
	  alpha: [].concat(projectRequest),
	  angery_blue: [].concat(creativeRequest)
	}
    
    //function to hide a array of arrays 
       var hide = function(){
           $j.each(arguments, function(i, item){
               for(y = 0; y < item.length; y++){
                  $j(item[y]).hide();
               }
           }
               );
       }
       //function to show a array of arrays
       var show = function(){
              $j.each(arguments, function(i, item){
                  for(y = 0; y < item.length; y++){
                   $j(item[y]).show();
                  }
              }
                  );
       }

   //check to see if you are on the end users request page
  // if(location.pathname === '/requests/new' || location.pathname === '/anonymous_requests/new') {
   //hide all the fields
   hide(hideAll);

      //monitor the dropdown field
      $j('#ticket_fields_104609').change(function (){ 
         //grab the value of the dropdown
         var userSelection = $j('#ticket_fields_104609').val();
		 hide(hideAll);
            if (userSelection.length > 0) show(moodFieldMap[userSelection]);
         });
//    }

  });


}());

You then build out arrays of the fields that you want to show or hide. When showing or hiding a field, there are two mandatory elements of the field and one optional that are needed in the array. The two mandatory are Title and custom field ID. The optional element is the ticket field description.

conditional_fields2.png

To hide the correct title or description, the jQuery function ‘contains:’ is used (as you can see in the code example above). To hide the title, the array includes ‘h3:contains(Division)’, which hides all titles that contain the word 'Division'. Hiding the description is done the same way: ‘p:contains(Which Division)’. To hide the field itself, use the format ‘#ticket_fields_ID’ (for example '#ticket_fields_20389142').

After you build out the arrays in the widget, you hide all the elements in the arrays using for loops and then start to monitor changes on the parent ticket field. Once the user has made a selection, you grab the value and use if statements to show or hide the elements.

20120229-nxw8rtxmuydpip4c8uhk78a527.jpg

Option 2: Required child fields

The other way to do condition fields is to rewrite the drop-down list options based on the selection in the parent field. The benefit to using this method is the child fields can be required. You still need to get the custom ticket field ID and build arrays, but the arrays will be the titles and values that you want to display when an option is selected in the parent field.

Here's the JavaScript code to create conditional fields with required child fields. You can also find the code on github.

(function () {
    /*create the various options you want to display 
	**each array needs to be built out with even number of members
	**in a tag, title format. 
	*/
    var option1 = ['epic','Epic','story','Story'];
	var option2 = ['problem','Problem','task','Task'];
	var option3 = ['question','Question','incident', 'Incident'];
	var fieldOption1 = ['teeth', 'Teeth', 'gums','Gums' ]
	var fieldOption2 = ['molar', 'Molar', 'tonge', 'Tounge']

	//this builds the dropdown list
    Buildoptions = {
        selected: function(value, name){ 
            return '<option value="'+value+'" selected="selected">'+name+'</option>';
        },
        notselected: function(value, name){
            return '<option value="'+value+'">'+name+'</option>';
        },
        clear: function(){
            return '<option value=""></option>';
        }
    }
	//goes through the selected array and builds the options 
	var makeSelection = function(theField, theArray) {
	        for ( x = 0; x < theArray.length; x = x + 2) { console.log('makeing select ' + theArray)
                $j(''+ theField +'').append(Buildoptions.notselected(theArray[x], theArray[x + 1]));
	        }
	    }

        //default options when page 1st loads 
	    $j("select#ticket_fields_20111097").html(Buildoptions.clear());
	    makeSelection('select#ticket_fields_20111097',option3);
	    //watch the root field for changes 
	    $j('#ticket_fields_109934').change( function(endUserselect){
            //grab the value of the dropdown
            var userSelection = $j('#ticket_fields_109934').val();
		    if( userSelection === 'teeth') { 
		        $j("select#ticket_fields_20111097").html(Buildoptions.clear());
			    makeSelection('select#ticket_fields_20111097',option2);
		    } 
		    if ( userSelection === 'gums' ) { 
		        $j("select#ticket_fields_20111097").html(Buildoptions.clear());
			    makeSelection('select#ticket_fields_20111097',option1);
		    } 
		    if ( userSelection === 'tonge'){
			    $j("select#ticket_fields_20111097").html(Buildoptions.clear());
		        makeSelection('select#ticket_fields_20111097',option3);
		    }
		    if ( userSelection === 'molar'){
			    $j("select#ticket_fields_20111097").html(Buildoptions.clear());
		        makeSelection('select#ticket_fields_20111097',option1);
		    }
	    });
	    $j('select#ticket_group_id').change( function(agentSelect){
            //grab the value of the dropdown
            var userSelection = $j('select#ticket_group_id').val();
            console.log('in change' + userSelection);
		    if( userSelection === '48491') { 
		        $j("select#ticket_fields_109934").html(Buildoptions.clear());
			    makeSelection('select#ticket_fields_109934',fieldOption2);
		    } else if ( userSelection === '81995' ) { 
		        $j("select#ticket_fields_109934").html(Buildoptions.clear());
			     makeSelection('select#ticket_fields_109934',fieldOption1);
		    }
	    });
    
    if(location.pathname.indexOf('tickets') >= 1) {
        $j('select#ticket_fields_109934').html(Buildoptions.clear());
        //default options when page 1st loads 
	    console.log(document.location.pathname);
	    $j.getJSON(document.location.pathname, function(ticketData){
	            console.log('ticket groupid ' + ticketData.group_id);

	            $j.each(ticketData.ticket_field_entries, function(i, item){
	               if ( item.ticket_field_id === 109934) {
	                    if( item.value === 'teeth' ) { 
	                        $j('select#ticket_group_id').val('81995');
	                        $j('select#ticket_group_id').change();
	                        $j("select#ticket_fields_20111097").html(Buildoptions.clear());
	                        makeSelection('select#ticket_fields_20111097',option2);
	                    }
	                    if ( item.value === 'gums'){
	                        $j('select#ticket_group_id').val('81995');
	                        $j('select#ticket_group_id').change();
	                        $j("select#ticket_fields_20111097").html(Buildoptions.clear());
            			    makeSelection('select#ticket_fields_20111097',option1);
	                    }
	                    if ( item.value === 'molar'){
	                        $j('select#ticket_group_id').val('48491');
	                        $j('select#ticket_group_id').change();
	                        $j("select#ticket_fields_20111097").html(Buildoptions.clear());
	                        makeSelection('select#ticket_fields_20111097',option1);
	                    }
	                    if ( item.value === 'tonge'){
	                        $j('select#ticket_group_id').val('48491');
	                        $j('select#ticket_group_id').change();
	                        $j("select#ticket_fields_20111097").html(Buildoptions.clear());
	                        makeSelection('select#ticket_fields_20111097',option3);
	                    }
	                    $j('#ticket_fields_109934').val(item.value)
	               }
	               if ( item.ticket_field_id === 20111097) {
                       console.log('20111097 ' + item.value)        
   	                $j('#ticket_fields_20111097').val(item.value)
   	               }
                   
                    
	            });
	       }
	    );
    }
}());

To create the various options you want to display, each array needs to be built out with an even number of members in a tag and title format.

conditional_fields4.png

The first thing you have to do is figure out what your default options are going to be. The following function clears all the values and rebuilds itself with the default values.

conditional_fields5.png

Then, you just watch the parent ticket field for changes and then, based on the user's selection, call the build function with the correct array.

conditional_fields6.png

Have more questions? Submit a request

Comments

  • Avatar
    Skip Moore

    Fixed errors in code examples in the topic and github

  • Avatar
    Arnaud de Theux

    That is awesome! Thanks so much.

  • Avatar
    Ani Niow

    Fantastic. Is there a chance we could see a demo of this somewhere? Thanks!

  • Avatar
    Garon Davis

    Great stuff.  I will probably use this very soon.

  • Avatar
    Ryan Nguyen

    Thanks alot! It works perfectly!

     

    A minor comment: for non required child field code on github , line 57 can be improved by changing to

          if (userSelection.length > 0) show(moodFieldMap[userSelection]);

    to prevent null item when the user selects nothing in the parent field

  • Avatar
    Skip Moore

    @Ryan Nguyen, thanks for the tip. I have updated the source and the document. 

    Cheers

    Skip 

  • Avatar
    Johan Dekker

    I am a complete noob with Zendesk and cannot get this to work.

    Steps:

    1. Created a new widget

    2. I have copied the code above from sample 1, mod the variables

    When i go the user request page all the fields are still visible

    What am I missing?

  • Avatar
    Jay Heath

    Will such drop-downs also be conditional for agents, or just end-users? For example, if something is assigned to the "facilities" group then show the fields? As you might imagine, our facilities tickets have a need for different ticket fields than our tech support tickets.

  • Avatar
    Skip Moore

    @Jay they will work for both agents and end-users. If you have requirements just for agents use a widget with permissions for agents only 

  • Avatar
    Taylor Bird

    So I got most of this working, but it appears that when a multi-tier Drop-down is used for the parent field, the .change() event is never fired.

     

    Any thoughts?

  • Avatar
    Patrick B.

    Just forgive a Noob-Question: Where do I have to add this coding to get it work?

    Best regards,

    Patrick

  • Avatar
    Joe D

    I second the motion for a demo sometime.  Also, I'm a bit confused as to what the chunk of code below is for in Option 1, and what (if anything) needs to be changed here to work outside of the example:

     

    $j(document).ready(function() {
    //this builds a map based on the selection of the dropdown field values
    moodFieldMap = {
    alpha: [].concat(projectRequest),
    angery_blue: [].concat(creativeRequest)
    }

  • Avatar
    Hadas

    Can someone please explain this part in "Option 2 - Required Child FIelds"?

     

    $j('select#ticket_group_id').change( function(agentSelect){
    //grab the value of the dropdown
    var userSelection = $j('select#ticket_group_id').val();
    console.log('in change' + userSelection);
    if( userSelection === '48491') {
    $j("select#ticket_fields_109934").html(Buildoptions.clear());
    makeSelection('select#ticket_fields_109934',fieldOption2);
    } else if ( userSelection === '81995' ) {
    $j("select#ticket_fields_109934").html(Buildoptions.clear());
    makeSelection('select#ticket_fields_109934',fieldOption1);
    }
    });
     
    Can you please clarify what this part of the code is doing and also - I don't understand where these values '48491' and '81995' are coming from.
    Thanks in advance,
    Hadas

  • Avatar
    Hadas

    OK, I think I've figured it out... I assume that's the group ID in your specific environment.

     

    Thanks,

    Hadas

  • Avatar
    Support Zendesk

    I'm sorry, but where do I put my custom id field from my custom drop down menu? Mine is 21648478 but in the above examples I'm seeing multiple ticket_fields_(number). Also, if someone could clarify the question from Hadas, in case that's relevant.

     

    It might help non-coders like myself if the code above simply had a variable we filled once (like my custom field ID 21648478) and the rest sorted itself.

  • Avatar
    Skip Moore

    Your field that is the control or monitor field should look like this

    $j('#ticket_fields_21648478').change(function (){
    //grab the value of the dropdown
    var userSelection = $j('#ticket_fields_21648478').val();
    hide(hideAll);
    if (userSelection.length > 0) show(moodFieldMap[userSelection]);
    });

    The moodFieldMap is just a way of mapping the select value to a list of actions for example show the project request fields when alpha is selected

  • Avatar
    Dan Goldman

    Can someone point me to where I can find the reference documentation for all the Zendesk screen fields (attributes, methods, etc)?

    Specifically, where can I find the reference for methods such as parent(), up()?, for attributes for value, description, etc?

    I want to set some fields by default when creating a new ticket. If someone can provide guidance on that it would be greatly appreciated.

    I looked a the existing documentation on the Developer site but when I compare that documentation with posted javascript code samples I can't find references for much of what I see in the code.

    Thanks.

  • Avatar
    Skip Moore

    we don't have a published reference document about the DOM. How are you getting the data to set the fields? Could it be passed by URL parameter? 

  • Avatar
    Dan Goldman

    I can set the field values to literal strings in the javascript.

  • Avatar
    Skip Moore

    Ok in that case you just have to inspect the DOM and find the strings you want to set. 

    Cheer

    Skip 

  • Avatar
    Dan Goldman

    I don't think I explained myself correctly. Also you already said you don't publish a reference for the DOM.

    In any case, I know what literal string I need to set the field to. It's one that I made up. What I don't know is HOW to set the field value in javascript.

    Thanks.

  • Avatar
    Skip Moore

    Oops sorry for my confusion you can do it like this 

    jQuery('#ticket_fields_20541671').val('test');

  • Avatar
    Dan Goldman

    I tried the above and the result was not what I wanted.

    1. The field values are still not getting set to the string passed into the val method

    2. The fields for which I am trying to set the values are set to hidden based on the user's group. When I try and set the values they are made visible in spite of my having removed them from the screen. See code snippet below.

    The fiields in question are dropdown lists. They do not have "NA" as an option since Zendesk will not let you use the same dropdown value for different dropdown lists (seems like a strange requirement). I tried it with values that are in the dropdown lists and that did not work either - same results as above. The code I am using originated with Tal Admon in the "How to: Hide specific fields from certain groups of agents" post.

    Thanks

    else if (groupname == "Cust Svc - Contracting")

    {

      jQuery("#ticket_fields_21519533'').val("NA");

      jQuery("#ticket_fields_21543828'').val("NA");

      $("#ticket_fields_21519533").parent().remove();

      $("#ticket_fields_21543828").parent().remove();

    }

  • Avatar
    Skip Moore

    In the case of setting dropdown fields to null use 

      jQuery("#ticket_fields_21519533").val("");

  • Avatar
    Dan Goldman

    Same problem.

    The fields being removed appear

    The fields being set are not set. Note - it is not necessarily about setting the fields to null values. I'd actually prefer "NA". Also, the fields being set are required.

    To completely describe the objective - I am trying to set default values for dropdown fields that are required but not displayed.

    Thanks

  • Avatar
    Andre Nadimi

    I was wondering how to implement this but base the conditions on what Group the assignee is in?

  • Avatar
    Naimish

    I am trying to create a simple conditional field which shows up when customer selects a particular option from the droplist. I am using the below code but its not working for me. Can anyone point out whats wrong and how to get around it ?

    var cond_field = $j("ticket_fields_21781962");

    if( cond_field ) {

    var status_field = $("ticket_fields_21505721");

    var onDepChange = function() {

    if( status_field.value == 'Claim' ) {

    cond_field.up().show();

    }

    else {

    cond_field.up().hide();

    }

    }

    status_field.observe('change', onDepChange );

    onDepChange();

    }

  • Avatar
    Hadas

    Hi Naimish,

    I think one of the problems is that you don't store the selected value.

    The following is taken from a customization that I did and is working well, so maybe you can base your code on this. I wanted to show a website url field only if my chosen select box value was "ps". It also shows and hides the label (h3), because you want to show/hide it accordingly:

     

    var website_url_field = $("ticket_fields_21811678"); //the url text box

    if( website_url_field ) {

    var website_url_field_stored_value = website_url_field.value;

    var onDepChange = function() {

    var the_chosen_field = $j('#ticket_fields_21798956').val();

    if( the_chosen_field == 'ps' ) {

    website_url_field.up().show();

    $j('h3:contains(Website URL)').show();

    website_url_field.value=website_url_field_stored_value;

    }

    else {

    website_url_field.up().hide();

    $j('h3:contains(Website URL)').hide();

    website_url_field_stored_value = website_url_field.value;

    website_url_field.value="";

    }

    }

    observeDeliverablesChange( onDepChange );

    onDepChange();

    }

     

     

    Hope this helps.

    Hadas

  • Avatar
    Naimish

    Thanks Hadas. I am trying with this code now but it seems there is no change. 

    var website_url_field = $("ticket_fields_21781962"); //Order number field

    if( website_url_field ) {

    var website_url_field_stored_value = website_url_field.value;

    var onDepChange = function() {

    var the_chosen_field = $j('#ticket_fields_21505721).val();

    if( the_chosen_field == 'Claim' ) {

    website_url_field.up().show();

    $j('h3:contains(Order number)').show();

    website_url_field.value=website_url_field_stored_value;

    }

    else {

    website_url_field.up().hide();

    $j('h3:contains(Order number)').hide();

    website_url_field_stored_value = website_url_field.value;

    website_url_field.value="";

    }

    }

    observeDeliverablesChange( onDepChange );

    onDepChange();

    }

  • Avatar
    Andrew Mills

    Great concept - I THINK this is what I am looking for, but goodness, incredibly complex for the non-techo Zendesk users.  A native ZD solution would be good.  Conditional form fields... is that what this achieves?

    For me, specifcially I would like a different set of form fields for different groups, our span a range of support issues (Mobile phones, PCs and some really different stuff (general queries) - building a generic form to handle this is very awkward.

Please sign in to leave a comment.