Support from Acquia helps fund testing for Drupal Acquia logo

Comments

gabriel.camby’s picture

Hey there,

I'm posting a workaround based on Tim Sherratt rewrite of the original workaround using jQuery. It transforms a select list to a multiple select list with sub categories. You need to configure Hierachical Select to display your list like this:

Cat 1
-Subcat 11
-Subcat 12
Cat 2
-Subcat 21
-Subcat 22

This workaround use the dash separator to parse the vocabulary structure; it's its only weakness I think. I tweaked it a bit to make it work on most browsers; mostly the "selected" part and wrapped it up in a Drupal behavior for those ajax views.

Voila; feel free to use it by changing the jQuery selector #edit-field-categories to your liking. Load the javascript on your Drupal either via template (drupal_add_js(file.js); or <script/>)or via .info file.

dgastudio’s picture

FileSize
84.97 KB

soon on codecanyon
screen

dgastudio’s picture

Views Hierarchical Taxonomy Filter

Views Hierarchical Taxonomy Filter extends Views with an option of using hierarchical taxonomy select in a capacity of the exposed filter.

The module adds to Views a special filter that enables selecting taxonomy terms of the specified vocabulary consecutively.

The selection considers terms hierarchy and uses AJAX for set of “select” type fields, in which a value of each next depends on the value of the previous.

It works in combination with other taxonomy filters, including the same filter, used for the other vocabulary

Yazzbe’s picture

FileSize
4.48 KB

Hi Kervi,

I just went to CodeCanyon and bought your module. With 2 or 3 dependent select lists this works great :)

BUT if we combine it with a keyword search (text box) in the same views exposed filter (see attach search box), then we get a nasty AJAX error :(

PDOException: You cannot serialize or unserialize PDO instances in DrupalDatabaseCache->set() (line 463 of /host/artmania/mydrupal.be/public/includes/cache.inc).

Is there a workaround for this ?

Many thanks,
Yazzy

Yazzbe’s picture

FileSize
11.32 KB

Sorry Kervi, another issue ...

When I have 2 search blocks on the same page (in the same region) then the values are pickup by both boxes simultaniously (see attach) if they use the same taxonomy. So the dependent listboxes are not populated correctly.

I see in the html code that the id's of select lists using the same taxonomy terms are identical, across different search blocks.

Is there a way to make the id's of form fields using the same taxonomy terms unique, so multiple search boxes can be used on the same page?

thanks
Yazzy

Barto.G’s picture

dgastudio’s picture

thank you for the report, i'll work on it.

liminu’s picture

#1 works, i change #edit-field-categories and #edit-field-docu-categories with the id of the select.
Thanks

emberhxc’s picture

Hi guys,

I'm also using kervi's module, and i'm having two problems:

first, it returns a Strict Warning/Strict Standards

Declaration of views_hst_filter_handler_filter::exposed_validate() should be compatible with that of views_handler::exposed_validate()

And second, i get and incompatibility with the better exposed filter module, because it doesn't have a filter identifier... anyone know how to work around this?

dkre’s picture

Thanks G4be, really nice solution.

From my testing this good in FF/Chrome and IE9-7.

osorkon5513’s picture

Hello,
Thanks for the script. I implement it on my site, but I have a problem when the list is as follows:
Cat 1
-Subcat 11
--Subcat 111
-Subcat 12
--Subcat 121
Cat 2
-Subcat 21
--Subcat 211
-Subcat 22
--Subcat 221
Can you help me!!!

osorkon5513’s picture

#1
Hello,
Thanks for the script. I implement it on my site, but I have a problem when the list is as follows:
Cat 1
-Subcat 11
--Subcat 111
-Subcat 12
--Subcat 121
Cat 2
-Subcat 21
--Subcat 211
-Subcat 22
--Subcat 221
Can you help me!!!

danielnolde’s picture

#3 is a blatant violation of both GPL with legal relevancy and a horrible misbehaviour of community rules. Having a fix of open source software ready and not contributing it back but instead withholding it illegally and trying to close-source it to earn money from selling has to be contributed back by contract (GPL) is contrary to our beliefs and rules and can't be tolerated in any way.

@Admins/Mods and @Maintainer: Please care so that #3 is removed from this issue.

Has already bought someone the code in #3 and can post it here if it's good? Would helpful and be totally legal!! => GPL!

infines’s picture

@danielnolde This has already been discussed and resolved about in another issue. Please try to stay to the issue at hand. Here is the other issue:

http://drupal.org/node/1170192

osorkon5513’s picture

if you want to work with a select deep 3 example:
Category1
-SubCategory11
- SubSubCategory111
-SubCategory12
- SubSubCategory121
Category2
-SubCategory21
- SubSubCategory211
-SubCategory22
- SubSubCategory221

Just change the counter:

/ / Build a node for each option and attach it Appropriately
   for (var i = 0; i <options.length; i + +) {
     var option = $ (options [i]);
     var depth = 1;

Thanks g4be for your script

chandan.drupalchamp’s picture

I need also 3 level dependent categories and i have used filter-hierarchy-select.js but i have not result.

may you please say how I'll use it.

Thanks

chandan.drupalchamp’s picture

I need also 3 level dependent categories and i have used filter-hierarchy-select.js but i have not result.

may you please say how I'll use it.

Thanks

augustynen’s picture

Yes, I need the 3 level to,
it's a beauty this one: http://codecanyon.net/item/views-hierarchical-taxonomy-filter/full_scree...

If i just knew where to start to get this one working
Ohw, sorry, i would have to buy it.

And so strange, that for something that's working on the nodepages, but not in views, I just can't believe that something like this is SOW complicated.

I have a solution for 2 levels but I can't get it to work for 3 levels.
Just put the code in the head of your page (html.tpl.php).

<script>
    /*
 * Notes:
 * - The fiddle does not use Drupal.t(), so you must do it when implementing it on your site.
 */
(function($) {
    $(document).ready(function() {
        var parents = {};
        
        var srcSelect = 'edit-term-node-tid-depth'; // id of the select containing the original, flat list of options
        // Any option having this character(s) at least once will be considered child
        // It is assumed this "magic" word is found before the part of the option that
        // must be preserved when put into the level2 select
        var childChar = '-';
        var childCharLength = 1; // Length of childChar
        var level1Label = '- GAMMA -'; // "all" values text for level 1 select
        var level2Label = '- MODEL -'; // "all" values text for level 2 select
        var level1Id = 'gamma'; // Id to use for the level1 select
        var level2Id = 'model'; // Id to use for the level2 select
        var allOptionValue = 'Alle'; // value of the "all" option in the srcSelect
        
        // Returns true if the text of the option has the childChar
        function isChildItem(opt) {
            var optText = $(opt).attr('text');
            return optText.indexOf(childChar) == -1 ? false: true;
        }
        
        // Stores the latest parent found
        var curParentVal = null;
        // Clones an option to the appropriate select in the hierarchy
        function addOption(parent, child, opt) {
            var optVal = $(opt).attr('value');
            var optText = $(opt).attr('text');
            var childCharPos = optText.indexOf(childChar);
            var cloneOpt = $(opt).clone();
            if (! isChildItem(opt)) {
                $('#' + parent).append(cloneOpt);
                curParentVal = optVal;
            } else {
                var childOptText = optText.slice(childCharPos+childCharLength);
                // Prepares the clone before appending it
                $(cloneOpt)
                    .addClass("sub_"+curParentVal)
                    .attr('text', childOptText);
                $('#' + child).append(cloneOpt);
                // Stores the child:parent relationship in the parents object
                parents[optVal] = curParentVal;
            }
        }
        
        // Turns on the selected attribute on the option whose value is optValue
        function setSelectValue(selectId, optValue) {
            return $('#'+selectId).attr('value', optValue);
        }
        
        // Clone only the .sub_X options from hidden select, X being current parent's value
        // and use it as new set of options for the child select
        function refreshChildOptions(parent, child, isSubselectOptional) {
            var parentValue = $('#'+parent).attr('value');
            // Hide to be nice with IE
            $('#' + child)
                .hide()
                .html($("#" + parent + child + " .sub_" + parentValue).clone());
            if (isSubselectOptional) {
                var cloneOpt = $('#'+srcSelect+' option[value='+allOptionValue+']').clone();
                $(cloneOpt)
                    .attr('value', parentValue)
                    .attr('text', level2Label);
                $('#' + child)
                    .prepend(cloneOpt);
            }
            // Show it again
            $('#' + child).show();
        }
        
        // Generate City - Area separated selects from original one. Initially hide them.
        $("#"+srcSelect+"-wrapper .form-item")
            .append("<select id='"+level1Id+"' class='form-select' style='display: none;'></select>")
            .append("<select id='"+level2Id+"' class='form-select' style='display: none;'></select>");
        
        // Iterate over the original options to add them to the dependant dropdowns
        $("#"+srcSelect+" option").each(function(index, item) {
            var optVal = $(item).attr('value');
            if (optVal != allOptionValue) {
                addOption(level1Id, level2Id, item);
            }
        });
        // Add the "all" option to the level1 select, do cloning just for convenience (also seems to be more compatible with IE)
        allOpt = $('#'+srcSelect+' option:first')
            .clone()
            .attr('text', level1Label);
        $("#"+level1Id).prepend(allOpt);
    
        function makeSublist(parent, child, isSubselectOptional, childVal) {
            // Add a hidden select to store the full possibilities for child, without filtering from parent's current value
            $("#"+srcSelect+"-wrapper .form-item").append("<select style='display:none' id='" + parent + child + "'></select>");
            // Get all the options from child and put them in hidden select
            $('#' + parent + child).html($("#" + child + " option"));
    
            // Read current parent's value
            var parentValue = $('#' + parent).attr('value');
            refreshChildOptions(parent, child, isSubselectOptional);
            
            // Select the default child option
            childVal = (typeof childVal == "undefined") ? "" : childVal;
            setSelectValue(child, childVal);
    
            // Bind to change event on parent select
            $('#' + parent).change(function() {
                var parentValue = $('#' + parent).attr('value');
                $('#'+srcSelect).attr('value', parentValue);
                refreshChildOptions(parent, child, isSubselectOptional);
                
                // Be nice to IE8
                $('#' + child + ' option:selected').removeAttr('selected');
                setSelectValue(child, parentValue);
                
                if (parentValue != allOptionValue) {
                    $('#' + child).focus();
                }
            });
            // Bind to change event on child select
            $('#' + child).change(function() {
                var childValue = $('#' + child).attr('value');
                $('#'+srcSelect).attr('value', childValue);
            });
        }

        makeSublist(level1Id, level2Id, true);
        
        // Ensure proper initialization of dependant dropdowns
        var initValue = $('#'+srcSelect).attr('value');
        var parentValue = parents[initValue];
        var level1Value = typeof parentValue == "undefined" ? initValue: parentValue;
        setSelectValue(level1Id, level1Value);
        refreshChildOptions(level1Id, level2Id, true);
        setSelectValue(level2Id, initValue);
        
        $('#'+srcSelect).hide(); // Comment to see the original select being driven by the new ones
        $('#'+level1Id).show(); // Only show the new selects at the very end, when we're sure it's all been set up correctly
        $('#'+level2Id).show();
    });
})(jQuery);

  </script>

But it's like I said, a 2 level solution.
Is there any one that can help me?

augustynen’s picture

Really, somebody that can help me make this script work for 3 levels?
I can read and edit a little bit PHP, but something big like this... I don't know how to do that.

I think that people would be happy to see it working for 3 levels.

Please?

augustynen’s picture

I already made some changes to it. But they result in not working of the script at all.
The thing is the middle child can be a value, when there are 3 levels.
But when I copy the line with .attr('text', level2Label); I get a syntax error. Really don't get it how you do this...

  <script>
    /*
 * Notes:
 * - The fiddle does not use Drupal.t(), so you must do it when implementing it on your site.
 */
(function($) {
    $(document).ready(function() {
        var parents = {};
        
        var srcSelect = 'edit-term-node-tid-depth'; // id of the select containing the original, flat list of options
        // Any option having this character(s) at least once will be considered child
        // It is assumed this "magic" word is found before the part of the option that
        // must be preserved when put into the level2 select
        var childChar = '-';
		var childChar2 = '--';
        var childCharLength = 1; // Length of childChar
		var childCharLength2 = 2; // Length of childChar
        var level1Label = '- GAMMA -'; // "all" values text for level 1 select
        var level2Label = '- MODEL -'; // "all" values text for level 2 select
		var level3Label = '- UITVOERING -'; // "all" values text for level 2 select
        var level1Id = 'gamma'; // Id to use for the level1 select
        var level2Id = 'model'; // Id to use for the level2 select
		var level3Id = 'uitvoering'; // Id to use for the level2 select
        var allOptionValue = 'Alle'; // value of the "all" option in the srcSelect
        
        // Returns true if the text of the option has the childChar
        function isChildItem(opt) {
            var optText = $(opt).attr('text');
            return optText.indexOf(childChar) == -1 ? false: true;
        }
		
		// Returns true if the text of the option has the second childChar
		function isChildItem2(opt) {
            var optText2 = $(opt).attr('text');
            return optText2.indexOf(childChar2) == -2 ? false: true;
        }
        
        // Stores the latest parent found
        var curParentVal = null;
		// Stores the latest child found
        var curChildVal = null;
        // Clones an option to the appropriate select in the hierarchy
        function addOption(parent, child, child2, opt) {
            var optVal = $(opt).attr('value');
            var optText = $(opt).attr('text');
            var childCharPos = optText.indexOf(childChar);
			var childCharPos2 = optText2.indexOf(childChar2);
            var cloneOpt = $(opt).clone();
           
		    if (! isChildItem(opt)) {
                $('#' + parent).append(cloneOpt);
                curParentVal = optVal;
            } else {
                var childOptText = optText.slice(childCharPos+childCharLength);
                // Prepares the clone before appending it
                $(cloneOpt)
                    .addClass("sub_"+curParentVal)
                    .attr('text', childOptText);
                $('#' + child).append(cloneOpt);
                // Stores the child:parent relationship in the parents object
                parents[optVal] = curParentVal;
            }
			
			if (! isChildItem2(opt)) {
                $('#' + parent).append(cloneOpt);
                curChildVal = optVal;
            } else {
                var childOptTex2t = optText2.slice(childCharPos2+childCharLength2);
                // Prepares the clone before appending it
                $(cloneOpt)
                    .addClass("sub_"+curParentVal)
                    .attr('text', childOptText2);
                $('#' + child).append(cloneOpt);
                // Stores the child:parent relationship in the parents object
                parents[optVal] = curChildVal;
            }
        }
        
        // Turns on the selected attribute on the option whose value is optValue
        function setSelectValue(selectId, optValue) {
            return $('#'+selectId).attr('value', optValue);
        }
        
        // Clone only the .sub_X options from hidden select, X being current parent's value
        // and use it as new set of options for the child select
        function refreshChildOptions(parent, child, isSubselectOptional) {
            var parentValue = $('#'+parent).attr('value');
            // Hide to be nice with IE
            $('#' + child)
                .hide()
                .html($("#" + parent + child + child2 +" .sub_" + parentValue + childValue).clone());
            if (isSubselectOptional) {
                var cloneOpt = $('#'+srcSelect+' option[value='+allOptionValue+']').clone();
                $(cloneOpt)
                    .attr('value', parentValue)
                    .attr('text', level2Label);
                $('#' + child)
                    .prepend(cloneOpt);
            }
            // Show it again
            $('#' + child).show();
        }
        
        // Generate City - Area separated selects from original one. Initially hide them.
        $("#"+srcSelect+"-wrapper .form-item")
            .append("<select id='"+level1Id+"' class='form-select' style='display: none;'></select>")
			.append("<select id='"+level2Id+"' class='form-select' style='display: none;'></select>")
            .append("<select id='"+level3Id+"' class='form-select' style='display: none;'></select>");
        
        // Iterate over the original options to add them to the dependant dropdowns
        $("#"+srcSelect+" option").each(function(index, item) {
            var optVal = $(item).attr('value');
            if (optVal != allOptionValue) {
                addOption(level1Id, level2Id, level3Id,item);
            }
        });
        // Add the "all" option to the level1 select, do cloning just for convenience (also seems to be more compatible with IE)
        allOpt = $('#'+srcSelect+' option:first')
            .clone()
            .attr('text', level1Label);
        $("#"+level1Id).prepend(allOpt);
    
        function makeSublist(parent, child, child2, isSubselectOptional, childVal) {
            // Add a hidden select to store the full possibilities for child, without filtering from parent's current value
            $("#"+srcSelect+"-wrapper .form-item").append("<select style='display:none' id='" + parent + child + child2 + "'></select>");
            // Get all the options from child and put them in hidden select
            $('#' + parent + child).html($("#" + child + " option"));
    
            // Read current parent's value
            var parentValue = $('#' + parent).attr('value');
            refreshChildOptions(parent, child, isSubselectOptional);
            
            // Select the default child option
            childVal = (typeof childVal == "undefined") ? "" : childVal;
            setSelectValue(child, childVal);
    
            // Bind to change event on parent select
            $('#' + parent).change(function() {
                var parentValue = $('#' + parent).attr('value');
                $('#'+srcSelect).attr('value', parentValue);
                refreshChildOptions(parent, child, isSubselectOptional);
                
                // Be nice to IE8
                $('#' + child + ' option:selected').removeAttr('selected');
                setSelectValue(child, parentValue);
                
                if (parentValue != allOptionValue) {
                    $('#' + child).focus();
                }
            });
            // Bind to change event on child select
            $('#' + child).change(function() {
                var childValue = $('#' + child).attr('value');
                $('#'+srcSelect).attr('value', childValue);
            });
        }

        makeSublist(level1Id, level2Id, level3Id, true);
        
        // Ensure proper initialization of dependant dropdowns
        var initValue = $('#'+srcSelect).attr('value');
        var parentValue = parents[initValue];
        var level1Value = typeof parentValue == "undefined" ? initValue: parentValue;
        setSelectValue(level1Id, level1Value);
        refreshChildOptions(level1Id, level2Id, true);
        setSelectValue(level2Id, initValue);
        
        $('#'+srcSelect).hide(); // Comment to see the original select being driven by the new ones
        $('#'+level1Id).show(); // Only show the new selects at the very end, when we're sure it's all been set up correctly
        $('#'+level2Id).show();
		$('#'+level3Id).show();
    });
})(jQuery);

  </script>
Saratt’s picture

FileSize
4.74 KB

I have been using the following script(from this thread or found it in another thread) for many views now. It works perfectly for 3 levels. All you have to change is the id of the first dropdown in line 4, where I have #edit-term-node-tid-depth.

Preface: In my case I have a view with an exposed filter. For example this is part of the filter before I use the script.

Financial Management
-Travel
--Travel Management Center(TMC).

I attached the result that I get when I use the script in the view.

<script type="text/javascript">
(function($){
$(document).ready(function() {
convertSelectElement(jQuery('#edit-term-node-tid-depth'));
});

function convertSelectElement(originalSelect) {
  // hide original list (which has depth)
  originalSelect.hide();
  // generate a graph of the objects
  var graph = createGraph(originalSelect.children());

  // create the appropriate number of select elements
  var selects = new Array();
  for (i = 0; i < 3; i++) {

    var select = $('<select />')
      .attr('id', 'select' + i)
      .addClass('form-select style-select')
      .css('display', 'none');

    originalSelect.parent().append(select);
    selects.push(select);
  }
 // $('.style-select').wrap('<div class="wrap-select" />');
  //$('#edit-field-tag-audience-tid-wrapper','#edit-field-news-date-value-wrapper').wrapAll(( $('<div>').addClass('wrapall')));
  $("<div class='more-filters'>")
    .insertBefore("#edit-field-tag-audience-tid-wrapper")
    .append($("#edit-field-tag-audience-tid-wrapper, #edit-changed-wrapper"));

  // populate our first select appropriately and show it
  populateSelect(selects[0], graph);
  selects[0].show();



  // set up a listener
  selects[0].bind('change.select-0', function(){
      optionSelected(graph, selects, 0, originalSelect);
  });

  // set the inital selection is per originalSelect
  if (graph.initialSelection != null)
    initialSelection(graph.initialSelection, selects);
}


// recursively set the initial selection
function initialSelection(node, selects) {
  if (node.root == true) return;
  initialSelection(node.parent, selects);
  selects[node.depth - 1].val(node.value).attr('selected', true);
  selects[node.depth - 1].trigger('change.select-' + (node.depth - 1));
}


// what to do when an option is selected
function optionSelected(parent, selects, selectIndex, originalSelect) {
 

  // convenience
  var select = selects[selectIndex];
  var childIndex = selectIndex + 1;
  var selectedOption = select.children(':selected');

  // set the value of the original select element
  setOriginalSelect(originalSelect, selectedOption.val());

  // hide all children selects and unbind their listeners
  for (var i = childIndex; i < selects.length; i++) {
    selects[i].hide();
    selects[i].empty();
    selects[i].unbind('.select-' + i);
  }

  // find the node selected
  for (var i = 0; i < parent.children.length; i++) {
    if (parent.children[i].value == selectedOption.val()) {
      var node = parent.children[i];

      // if the node has children populate a select, add a listener, and show it
      if (node.children.length > 0) {
        populateSelect(selects[childIndex], node);
        selects[childIndex].bind('change.select-' + childIndex, function(){
          optionSelected(node, selects, childIndex, originalSelect);
        });
        selects[childIndex].show();
      }
      break;
    }
  }
}


// populate a select using a node's children
function populateSelect(select, parent) {
    select.append($('<option />')
      .html('- Section -')
      .val(parent.value));

    for (var i = 0; i < parent.children.length; i++) {
      select.append($('<option />')
        .html(parent.children[i].title)
        .val(parent.children[i].value));
    }

}


// set the value of the original select element
function setOriginalSelect(select, value) {
   if( $('#select1 option').length < 1 )
 {
   // $('.form-item-term-node-tid-depth div:nth-child(2)').append("<span> - 2nd!</span>");
    $('#edit-term-node-tid-depth-wrapper .form-item > .wrap-select + .wrap-select').css('display','none');
 }
else
{
      $('#edit-term-node-tid-depth-wrapper .form-item > .wrap-select + .wrap-select').css('display','block');
}
  select.val(value).attr('selected', true);
}


// build a graph of the vocabulary
function createGraph(options)
{
  var root = {
    root : true,
    depth : 0,
    parent : null,
    children : new Array(),
    title : 'root',
    value : 'All', 
    graphDepth : 0,
    initialSelection : null
  };

  var prev = root;
  // build a node for each option and attach it appropriately
  for (var i = 1; i < options.length; i++) {
    var option = $(options[i]);
    var depth = 1;
    var title = option.html();

    // strip the dashes, and remember how many there are as that
    // is the node's depth
    while (title.indexOf("-") == 0) {
      title = title.substring(1);
      depth++;
    }

    // keep track of how deep the graph goes
    if (depth > root.graphDepth) root.graphDepth = depth;

    var node = {
      root : false,
      depth : depth,
      children : new Array(),
      title : title,
      value : option.val()
    };

    var dDepth = depth - prev.depth;

    // decide where to put the new node
    // (there must be a simpler way of doing this)
    if (dDepth == 0) {
      node.parent = prev.parent;
      prev.parent.children.push(node); 
    }
    else if (dDepth > 0){
      node.parent = prev;
      prev.children.push(node);
    }
    else {
      while (dDepth++ < 0) {
        prev = prev.parent;
      }
      node.parent = prev.parent;
      prev.parent.children.push(node);
    }

    // finally track which node is initally selected
    if (option.attr("selected") != false) root.initialSelection = node;

    prev = node;
  }
  return root;
}
})(jQuery);
</script>
augustynen’s picture

Looks fantastic that .png, st455.
Don't get it to work thoug....

I guesse it has something to do with:

 // $('.style-select').wrap('<div class="wrap-select" />');
  //$('#edit-field-tag-audience-tid-wrapper','#edit-field-news-date-value-wrapper').wrapAll(( $('<div>').addClass('wrapall')));
  $("<div class='more-filters'>")
    .insertBefore("#edit-field-tag-audience-tid-wrapper")
    .append($("#edit-field-tag-audience-tid-wrapper, #edit-changed-wrapper"));

What do I do with this ID's ?
I've putted the code in my HEAD.
Do i have to put it somewhere else?

augustynen’s picture

FileSize
40.99 KB

Alright, sow i didn't put a jquery library for it:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
But now I got something else.

I have a dropdown menu that shows one option: all terms from all levels just right behind each other...

Very strange....

My code looks like:


<div class="views-exposed-widgets clearfix">
<div id="edit-term-node-tid-depth-wrapper" class="views-exposed-widget views-widget-filter-term_node_tid_depth">
<label for="edit-term-node-tid-depth">Gamma</label>
<div class="views-widget">
<div class="form-item form-type-select form-item-term-node-tid-depth">
<select style="display: none;" id="edit-term-node-tid-depth" name="term_node_tid_depth" class="form-select">
<option value="All" selected="selected">-  Kies  -</option>
<option value="2">Schuifdeurkasten</option>
<option value="61">---</option>
<option value="19">-Porta D</option>
<option value="21">-S-Box</option>
<option value="20">-Twinn</option>
<option value="9">-Accessoires</option>
<option value="28">General Storage</option>
<option value="62">---</option>
<option value="29">-Klasseerkasten</option>
<option value="30">-Kantoorbedientafeltje</option>
<option value="4">-Vestairekasten</option>
<option value="3">Draaideurkasten</option>
<option value="63">---</option>
<option value="27">-Base Line</option>
<option value="18">-Budgetline</option>
<option value="26">-Light</option>
<option value="11">-Accessoires</option>
<option value="5">Ladeblokken</option>
<option value="64">---</option>
<option value="60">-Projectline</option>
<option value="59">-Topline</option>
<option value="10">-Accessoires</option>
<option value="6">Bureaus</option>
<option value="65">---</option>
<option value="81">-Base</option>
<option value="22">-Connex</option>
<option value="69">--STD - bureau</option>
<option value="75">--STD - bench</option>
<option value="74">--X4 - bureau</option>
<option value="68">--O - bureau</option>
<option value="79">--Accessoires</option>
<option value="23">-Quad</option>
<option value="76">--T - bureau</option>
<option value="77">--H - Bench</option>
<option value="80">--Accessoires</option>
<option value="25">-System</option>
<option value="71">--T - bureau</option>
<option value="72">--H - bench</option>
<option value="73">--O - bench</option>
<option value="70">--U - bench</option>
<option value="78">--Accessoires</option>
<option value="7">-Vergadertafels</option>
<option value="57">-Accessoires</option>
<option value="31">Personal Storage</option>
<option value="66">---</option>
<option value="33">-Side table</option>
<option value="34">-Tower</option>
<option value="32">-Bridge</option>
<option value="1">Rolluikkasten</option>
<option value="67">---</option>
<option value="12">-Brevidex</option>
<option value="13">-Cube</option>
<option value="14">-Light</option>
<option value="15">-Performer</option>
<option value="16">-Powerflex</option>
<option value="17">-Accessoires</option>
</select>
</div>

End in my I put:

   <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
 <script type="text/javascript">
(function($){
$(document).ready(function() {
convertSelectElement(jQuery('#edit-term-node-tid-depth'));
});

function convertSelectElement(originalSelect) {
  // hide original list (which has depth)
  originalSelect.hide();
  // generate a graph of the objects
  var graph = createGraph(originalSelect.children());

  // create the appropriate number of select elements
  var selects = new Array();
  for (i = 0; i < 3; i++) {

    var select = $('<select />')
      .attr('id', 'select' + i)
      .addClass('form-select style-select')
      .css('display', 'none');

    originalSelect.parent().append(select);
    selects.push(select);
  }
 // $('.style-select').wrap('<div class="wrap-select" />');
  //$('#edit-field-tag-audience-tid-wrapper','#edit-field-news-date-value-wrapper').wrapAll(( $('<div>').addClass('wrapall')));
  $("<div class='more-filters'>")
    .insertBefore("##edit-term-node-tid-depth-wrapper")
    .append($("#edit-term-node-tid-depth-wrapper, #edit-changed-wrapper"));

  // populate our first select appropriately and show it
  populateSelect(selects[0], graph);
  selects[0].show();



  // set up a listener
  selects[0].bind('change.select-0', function(){
      optionSelected(graph, selects, 0, originalSelect);
  });

  // set the inital selection is per originalSelect
  if (graph.initialSelection != null)
    initialSelection(graph.initialSelection, selects);
}


// recursively set the initial selection
function initialSelection(node, selects) {
  if (node.root == true) return;
  initialSelection(node.parent, selects);
  selects[node.depth - 1].val(node.value).attr('selected', true);
  selects[node.depth - 1].trigger('change.select-' + (node.depth - 1));
}


// what to do when an option is selected
function optionSelected(parent, selects, selectIndex, originalSelect) {


  // convenience
  var select = selects[selectIndex];
  var childIndex = selectIndex + 1;
  var selectedOption = select.children(':selected');

  // set the value of the original select element
  setOriginalSelect(originalSelect, selectedOption.val());

  // hide all children selects and unbind their listeners
  for (var i = childIndex; i < selects.length; i++) {
    selects[i].hide();
    selects[i].empty();
    selects[i].unbind('.select-' + i);
  }

  // find the node selected
  for (var i = 0; i < parent.children.length; i++) {
    if (parent.children[i].value == selectedOption.val()) {
      var node = parent.children[i];

      // if the node has children populate a select, add a listener, and show it
      if (node.children.length > 0) {
        populateSelect(selects[childIndex], node);
        selects[childIndex].bind('change.select-' + childIndex, function(){
          optionSelected(node, selects, childIndex, originalSelect);
        });
        selects[childIndex].show();
      }
      break;
    }
  }
}


// populate a select using a node's children
function populateSelect(select, parent) {
    select.append($('<option />')
      .html('- Section -')
      .val(parent.value));

    for (var i = 0; i < parent.children.length; i++) {
      select.append($('<option />')
        .html(parent.children[i].title)
        .val(parent.children[i].value));
    }

}


// set the value of the original select element
function setOriginalSelect(select, value) {
   if( $('#select1 option').length < 1 )
{
   // $('.form-item-term-node-tid-depth div:nth-child(2)').append("<span> - 2nd!</span>");
    $('#edit-term-node-tid-depth-wrapper .form-item > .wrap-select + .wrap-select').css('display','none');
}
else
{
      $('#edit-term-node-tid-depth-wrapper .form-item > .wrap-select + .wrap-select').css('display','block');
}
  select.val(value).attr('selected', true);
}


// build a graph of the vocabulary
function createGraph(options)
{
  var root = {
    root : true,
    depth : 0,
    parent : null,
    children : new Array(),
    title : 'root',
    value : 'All',
    graphDepth : 0,
    initialSelection : null
  };

  var prev = root;
  // build a node for each option and attach it appropriately
  for (var i = 1; i < options.length; i++) {
    var option = $(options[i]);
    var depth = 1;
    var title = option.html();

    // strip the dashes, and remember how many there are as that
    // is the node's depth
    while (title.indexOf("-") == 0) {
      title = title.substring(1);
      depth++;
    }

    // keep track of how deep the graph goes
    if (depth > root.graphDepth) root.graphDepth = depth;

    var node = {
      root : false,
      depth : depth,
      children : new Array(),
      title : title,
      value : option.val()
    };

    var dDepth = depth - prev.depth;

    // decide where to put the new node
    // (there must be a simpler way of doing this)
    if (dDepth == 0) {
      node.parent = prev.parent;
      prev.parent.children.push(node);
    }
    else if (dDepth > 0){
      node.parent = prev;
      prev.children.push(node);
    }
    else {
      while (dDepth++ < 0) {
        prev = prev.parent;
      }
      node.parent = prev.parent;
      prev.parent.children.push(node);
    }

    // finally track which node is initally selected
    if (option.attr("selected") != false) root.initialSelection = node;

    prev = node;
  }
  return root;
}
})(jQuery);
</script>

End now nothing sows up any more.
What do I do wrong?

augustynen’s picture

I FOUND IT
OOOH
@st455 I could kiss you right now.

I just deleted the "---" in the taxonomy options and there it gose !
IT WORKED

HOERA - we say in Belgium !

Saratt’s picture

@augustynen I am glad it worked.
You can basically delete this. I had to add this for the view that I was working on. The hierarchical select has nothing to do with these lines.

 // $('.style-select').wrap('<div class="wrap-select" />');
  //$('#edit-field-tag-audience-tid-wrapper','#edit-field-news-date-value-wrapper').wrapAll(( $('<div>').addClass('wrapall')));
  $("<div class='more-filters'>")
    .insertBefore("#edit-field-tag-audience-tid-wrapper")
    .append($("#edit-field-tag-audience-tid-wrapper, #edit-changed-wrapper"));
augustynen’s picture

@st455 okay, thanks a lot !

benjmarr’s picture

@st455 this is great!! well done.

I had a question for you. Is it possible when only the parent is selected that it shows all child terms in the result?

Thanks Again

Saratt’s picture

@brandercreative I am not sure I understand your question right, but I think that is how it works. For example, the first level of dropdowns might show something like this.

Ford
Honda
Toyota

Only when you select one of these items a second dropdown should show up with the corresponding children. Until you select a term in the first dropdown, you dont see another dropdown. And only when you select a result in the second dropdown you will see a third dropdown with the corresponding grand children (if your list has 3 levels). Let me know if that answers your question.

benjmarr’s picture

@st455 yep that works as required this is what im after though

Say we have this structure-

Honda
-Civic
-CRV
-Prelude
-Odyssey

When i select honda it gives me the children and also the first term being - Choose- (see below)

// populate a select using a node's children
function populateSelect(select, parent) {
    select.append($('<option />')
      .html('- Choose -')
      .val(parent.value));

What i need to happen is when i dont select a child (Leave select box on -choose-) from the parent it returns all children under that parent in the result.

Make Sense?

benjmarr’s picture

Any Ideas? Is there another way to accomplish this? Is this code capable of being tweaked to add this functionally?

Saratt’s picture

@brandercreative, that depends on how you have the view setup, in the view if the exposed filter is Content:Has taxonomy terms with depth and in settings if you have depth > 1 it will return the children. Let me know if that helps.

benjmarr’s picture

unfortunately my view is showing profiles not content which removes

Content:Has taxonomy terms with depth

from the list of possible filters. Im going to look into wether its possible to rework the filter to work for profiles too.

Cheers

stefan.r’s picture

Priority: Critical » Major
Issue summary: View changes
jatinkumar1989’s picture

#1, works for me,

i change #edit-field-categories and #edit-field-docu-categories with the id of the select.

Thanks a lot :) @gabriel.camby

gumanov’s picture

If anyone is still looking for a workaround for HS Views integrations, here's what seems to work pretty good for me:

I installed both HS, and SHS (Simple Hierarchial Select).
SHS has decent Views integration, but it's missing some features I use in HS - so I am using both.

I modified SHS slightly, the portion of the code that identifies all fields that have the taxonomy_shs widget type.
I simply added an OR statement, to also include the taxonomy_hs widget types. This way SHS will be available as an exposed filter in Views to both HS as well as SHS fields.

file: shs.module, line 754, before

if ($instance['widget']['type'] == 'taxonomy_shs') {

file: shs.module, line 754, after
if (($instance['widget']['type'] == 'taxonomy_shs') || ($instance['widget']['type'] == 'taxonomy_hs')) {

and

file shs.module, line 762, before
if ($instance['widget']['type'] == 'taxonomy_shs') {

file shs.module, line 762, after
if (($instance['widget']['type'] == 'taxonomy_shs') || ($instance['widget']['type'] == 'taxonomy_hs')) {

I don't know if this is a great idea, I'm not a coding guru. But no issues so far :)

Proteo’s picture

@gumanov wow, it works beautifully! Thanks a lot.

FYI, in the latest version of SHS the lines you need to modify are 1086 and 1094 respectively, inside the _shs_get_instances() function.