2

I have two select boxes. The first is a list of the optgroups of the second. Both are needed for my query, but I would like to filter the second select to ONLY show the region optgroup and it's campuses when it's selected from the first.

Here is my code:

<html>
<body>
<select name="region">
    <option value="%">All</option>
    <option value="A">Northwest</option>
    <option value="B">North Central</option>
</select>
<select name="campus">
    <option value="%">All</option>
    <optgroup label="Northwest">
        <option value="1">Gary</option>
        <option value="2">Valparaiso</option>
        <option value="3">East Chicago</option>
    </optgroup>
    <optgroup label="North Central">
        <option value="4">South Bend</option>
        <option value="5">Elkhart</option>
        <option value="6">Warsaw</option>
    </optgroup>
</select>
</body>
</html>

So if someone selects Northwest from the first one, I want to use jQuery to filter down the second one so it now looks like so:

<select name="campus">
    <optgroup label="Northwest">
        <option value="1">Gary</option>
        <option value="2">Valparaiso</option>
        <option value="3">East Chicago</option>
    </optgroup>
</select>

Not even sure if this is possible and this is my first attempt at jQuery so I am lost. Thanks in advance.

exodar
  • 85
  • 2
  • 6

2 Answers2

5

Try to .hide() the other <optgroup>s, and .show() the one(s) you want.

Something like this:

$('select[name="region"]').change(function() {
    var $sel = $('select[name="campus"]'),
        val = $(this).val(),
        campus = $('option:selected', this).text();
    if (val === '%') {
        $('option,optgroup', $sel).show();
    }
    else {
        $('optgroup, optgroup > option', $sel).hide();
        $('optgroup[label="' + campus + '"]', $sel).children().andSelf().show();
    }
});​

You can't just hide the <optgroup>, you need to hide its children <option>s too.

DEMO: http://jsfiddle.net/rffwW/

EDIT: Seems that doesn't work in IE (and apparently Safari). Another answer suggested wrapping the <option>s in <span>s, let's try that:

$('select[name="region"]').change(function() {
    var $sel = $('select[name="campus"]'),
        val = $(this).val(),
        campus = $('option:selected', this).text();
    $('span > optgroup', $sel).unwrap();
    if (val !== '%') {
        $('optgroup:not([label="' + campus + '"])', $sel).wrap('<span/>');
    }
});​

DEMO: http://jsfiddle.net/rffwW/1/

Community
  • 1
  • 1
gen_Eric
  • 223,194
  • 41
  • 299
  • 337
  • Doesn't work in desktop Safari or iOS Safari. Need it to work in both. – exodar Jul 25 '12 at 15:36
  • @exodar: It works in Chrome. Sorry, I don't have Safari to test in. What do you mean "doesn't work"? What does it do? – gen_Eric Jul 25 '12 at 15:37
  • It doesn't do anything. You select from the first box and the second one remains a full list. – exodar Jul 25 '12 at 15:38
  • @exodar: Seems you can't hide ``s and ` – gen_Eric Jul 25 '12 at 15:41
  • @exodar: I found a bit of a hack here: http://stackoverflow.com/a/5414366 Maybe that'll work. – gen_Eric Jul 25 '12 at 15:44
  • Found another issue...when I submit the form, the campus list is no longer filtered. How do I re-run the function after the form is submitted and comes back? – exodar Jul 25 '12 at 17:38
  • Just set the value `$('select[name="region"]').val(val)`, and manually trigger the event `$('select[name="region"]').trigger('change')`. – gen_Eric Jul 25 '12 at 17:45
1

I came across a similar solution here: https://gist.github.com/robcowie/2267793

Here is the plugin adapted to work with select text rather then values:

$.fn.filterGroups = function( options ) {
    var settings = $.extend( {filterByText: true}, options);

    return this.each(function(){
        var $select = $(this);
        $select.data('fg-original-groups', $select.find('optgroup').clone()).children('optgroup').remove();

        $(settings.groupSelector).change(function(){
            var $this = $(this);

            var optgroup_label = $.trim($this.val().toUpperCase());
            if(settings.filterByText)
                optgroup_label = $.trim($('option:selected', $this).text());

            var $optgroup =  $select.data('fg-original-groups').filter("optgroup[label='" + optgroup_label + "']").clone();
            $select.children('optgroup').remove();
            $select.append($optgroup);
        }).change();

    });
};

To use the plugin add your selectors like (I'd prefer to use ID's):

$('select[name="campus"]').filterGroups({groupSelector: 'select[name="region"]' });

Courtenay
  • 109
  • 1
  • 4