Just combined the script on: https://github.com/AndrewIngram/jquery-select-hierarchy with some custom code to have a working multi-step taxonomy select widget.

First, I added an exposed filter for the vocabulary I want. I selected "Dropdown" as the selection type and marked "Show hierarchy in dropdown". Now I have a select list like that:

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

Then I added custom javascript as a global text area to the header of that view with input type PHP. Things to be careful:

1. Change this:#edit-field-country-city-tid option with your select list's id.
2. Change this:.form-item-field-country-city-tid select with your select list's class.
3. This method doesnt work for 3 or more level hierarchies but it should be easy to modify the code to achieve this.
4.Hide the original select list with CSS.

<script type="text/javascript">
(function ($) {
$(document).ready(function() { 

var $groupedOptionList = $("#edit-field-country-city-tid option");
var groupedItemList = [];
var lastParentChildIndex = 0;
var lastParentIndex = 0;
$groupedOptionList.each(function(index, item) {
    var itemText = $(item).text();
    var splitterCount = itemText.match(/\-/g) === null ? 0 : itemText.match(/\-/g).length;
    // root item
    if (splitterCount === 0) {
        groupedItemList[index] = {
            text: itemText,
            children: []
        };

        lastParentIndex = index;
        $(item).text(groupedItemList[lastParentIndex].text);
    }
    //  first child        
    else if (splitterCount === 1) {
        groupedItemList[lastParentIndex].children.push({
            text: itemText,
            children: []
        });
        lastParentChildIndex = groupedItemList[lastParentIndex].children.length - 1;
        $(item).text(groupedItemList[lastParentIndex].text + " > "+ groupedItemList[lastParentIndex].children[lastParentChildIndex].text.substring(1));
    }

});

$.fn.selectHierarchy = function(options) {
        var defaults = {
            separator: ' > ',
            hideOriginal: true,
            placeholder: '------'
        };
        var options = $.extend(defaults, options);
        var obj = $(this);
        var max_depth = 1;

        var choices = obj.find('option').map(function(){
            var val = $(this).val();

            if (val) {
                var txt = $(this).text();
                var segments = txt.split(options.separator);
                var depth = segments.length;

                if (depth > max_depth) {
                    max_depth = depth;
                }

                var result = {
                    label: txt,
                    short_label: segments[depth-1],
                    value: val,
                    depth: depth,
                    children: []
                };

                return result;
            }
        });

        var roots = [];

        // Build up child values
        for (var depth=1; depth<=max_depth; depth++) {
            $.each(choices, function() {
                var parent = this;

                if (parent.depth==depth) {
                    if (depth===1) {
                        roots.push(this);
                    }

                    $.each(choices, function() {
                        var child = this;
                        if (child.depth == depth+1 && child.label.match("^"+parent.label)==parent.label) {
                            parent.children.push(child);
                        }
                    });
                }
            });
        }

        if (options.hideOriginal) {
            obj.hide();
        }
        obj.wrap('<span class="drilldown-wrapper" />');
        obj.after('<select class="drilldown-1"><option value="">' + options.placeholder + '</option></select>');
        var root_select = obj.next();
                       
        root_select.data('depth', 1);
                            
        $.each(roots, function(){
            var opt = $('<option>');
            opt.val(this.value);
            opt.text(this.short_label);
            opt.data('node', this);
            root_select.append(opt);
        });
                                
        var change_handler = function(){
            var this_select = $(this);
            var opt = this_select.find('option:selected');
            var node = opt.data('node');
       
            if (this_select.val()) {
                obj.val(this_select.val());
            } else if (this_select.data('depth') > 1) {
                obj.val(this_select.prev().val());
            } else {
                obj.val('');
            }
               
            this_select.nextAll('select').remove();
                       
            // Check to see if there's any children, if there are we build another select box;
            if (node && node.children.length > 0) {
                this_select.after('<select><option value="">' + options.placeholder +'</option></select>');

                var next_select = this_select.next();
                next_select.addClass('drilldown-' + (node.depth + 1));
                next_select.data('depth', node.depth + 1);

                $.each(node.children, function(){
                    var opt = $('<option>');
                    opt.val(this.value);
                    opt.text(this.short_label);
                    opt.data('node', this);
                    next_select.append(opt);
                });
                next_select.change(change_handler);
}
        }
        root_select.change(change_handler);
    };

$('.form-item-field-country-city-tid select').selectHierarchy({ hideOriginal: false });

});
})(jQuery);
</script>

Comments

Sinan Erdem’s picture

Currently above code doesnt work well if you have dashes (-) inside a term. I will try to fix it as soon as possible.

kaizerking’s picture

If it could developed as module it will be great
Hope some one can do this

Barto.G’s picture

Here is a "module" that rewrites the options and then use the jquery-select-hierarchy plugin
https://github.com/guizmo/Multi-step-select-list-for-nested-taxonomy-as-...

ogo’s picture

Hi Guizmo

I tested your new module and the drill down seems to work fine (more than 2 levels), however the original filter field remains, also duplicating a new filter field (rewritten options) below the apply button of the form with a new field id now ending with "--2".

This result in the new drill down filter also below apply button. (Working fine)
It seems the problem is with the unset function not removing the original filter, or I am just not doing it right.

Jan Stroh

ogo’s picture

Guizmo

I figured it out and now i can say your "module" works fine at this stage. (Will test further)

In your readme file "line 16 and 17 the id of the widget (look for the select #id minus "edit-")"

Instead of Select ID

unset($form['field-name-tid']);
$form['field-name-tid'] = array(

i replace it with Select Name

unset($form['field_name_tid']);
$form['field_name_tid'] = array(

This worked for me.

Jan Stroh

kaizerking’s picture

My structure is 4 levels
HS widget is used to select the terms in my create form
HS Widget settings are :
1.Save only the deepest term
2. Force user to select the deepest term
3.Drop box enabled
4. Multiple values (3 values)

Now I want to create a view where i want to filter nodes by these terms
Can we do it using this? i mean after modifying the form id, Vocabulary ID field names etc
If it is possible, some directions are appreciated please

Baber Javed’s picture

This Looks Great. However once I apply the filters and the page gets refreshed the dropdowns do not retain their values, any way to fix this?

Sinan Erdem’s picture

In order to keep the values, the jquery-select-hierarchy script should be modified to get the selected value from the original dropdown and mark the value as selected in the new dropdowns. I dont have the JS skills to do it myself.

deepakrmali’s picture

Hi,
have you find any solutions for "dropdowns do retain their values"?

Thanks in advances.

deepakrmali’s picture

I have find the solutions for "dropdowns do retain their values" issue. https://github.com/AndrewIngram/jquery-select-hierarchy

kla2t’s picture

The dashes (or more precisely: hyphens) issue could be fixed for me by changing line 11 of the script to

    var splitterCount = itemText.match(/\B\-/g) === null ? 0 : itemText.match(/\B\-/g).length;

Prefixing the hyphen with the regular expression for "Not word boundary" excludes hyphens within composite words.

By the way, it is not necessary (and kind of strange) to put the javascript into the Views header. I preferred to save the whole script - without <script> tags, of course - into a separate .js-file ("multistep-select.js", for example) and load it in the theme info.

Besides, the original select list should not be hidden with CSS, which makes the whole filter invisible in case javascript is disabled unless you differentiate the CSS selector into .js and .nojs cases. Simply changing the value of "hideOriginal" to "true" at the end of the script does the trick, too.

Sinan Erdem’s picture

I found that using "hideOriginal" creates a problem with remembering the option selected when the new page opens. Please test this behavior befor using that function.

Sinan Erdem’s picture

If you add the js as a file and add it into theme, then, it will be loaded on all pages right? It is a very small file but it is unnecessary to be loaded on every page.

pinkonomy’s picture

Does this work with views Search api also?
Can this be ported to Drupal.org ? I think its better there to exist.
Cheers,
Sokratis

alireza.13’s picture

if possible give us a road map for your module.
step by step guide.

Katy Jockelson’s picture

In case this is useful for anyone else...

I got this working by adding guizmo's module and making the edits described within.
- In the .module file:
* line 12 change the ID of the whole form e.g. views-exposed-form-library-page
* line 16 and 17 the name of the widget (look for the select name minus "edit-") e.g. field_categories_tid_1
* line 21 and 32 same thing as above if you have another field to modify else delete that part
* line 45 put your vocabulary id
- In the .js file:
* line 114 change the ID of the actual select e.g. #edit-field-categories-tid-1

To keep the values in dropdowns on page refresh (after hitting apply), I had to download the latest version of the plugin from https://github.com/AndrewIngram/jquery-select-hierarchy and add the extra code to the js file (from comment: // After setting up the behavior, set the drilldown select lists to the correct values for forms with a default value.)

Note that you seemingly can't turn on ajax on your View.

I have one thing left to achieve which is to remove the placeholder from the initial dropdown - help welcome!

lbrassaw’s picture

Hi there, this is a superb solution for the site I'm working on, but would like to know how to modify a little more:

1) How to show all child items once the parent is selected? And not show 'All' of the parents. So it would build like this:

Parent 1 >
> All
> > Child 1.1
> > Child 1.2
> > Child 2.1
> > Child 2.2
> Child 1
> > Child 1.1
> > Child 1.2
> Child 2
> > Child 2.1
> > Child 2.2
Parent 2 >
> All
> > Child 3.1
> > Child 3.2
> > Child 4.1
> > Child 4.2
> Child 3
> > Child 3.1
> > Child 3.2
> Child 4
> > Child 4.1
> > Child 4.2

Et cetera. In the module file, I've disabled line 53 – $taxoArray['All'] = "-All-"; – which returns 'All' for the parents. Is there a way to specify this for only the children?

2) Can an 'All' function replace the 'placeholder' in the JavaScript file on line 96? I can't think of how to do this using what you've already built.

Thoughts? Many thanks!

Katy Jockelson’s picture

@guizmo

vdsh’s picture

I had a similar requirements and found this module: https://www.drupal.org/project/shs which did exactly the job out of the box

capynet’s picture

YOU made my day