Cascading Select
Cascading/filtering dropdowns plugin.
HTML
<select id="first">
<option value="selector">Select a filter</option>
<option value="1">Filter 1</option>
<option value="2">Filter 2</option>
<option value="3">Filter 3</option>
</select>
<select id="second">
<option filter="selector" value="selector">Select a value</option>
<option filter="1" value="1">(1) - Value 1</option>
<option filter="1" value="2">(1) - Value 2</option>
<option filter="1" value="3">(1) - Value 3</option>
<option filter="2" value="4">(2) - Value 4</option>
<option filter="2" value="5">(2) - Value 5</option>
<option filter="2" value="6">(2) - Value 6</option>
<option filter="2" value="7">(2) - Value 7</option>
<option filter="3" value="8">(3) - Value 8</option>
<option filter="3" value="9">(3) - Value 9</option>
<option filter="3" value="10">(3) - Value 10</option>
</select>
<select id="third">
<option value="selector">Select a value</option>
<option filter="1" value="1">(1) - Value 1</option>
<option filter="1" value="2">(1) - Value 2</option>
<option filter="1" value="3">(1) - Value 3</option>
<option filter="2" value="4">(2) - Value 4</option>
<option filter="2" value="5">(2) - Value 5</option>
<option filter="2" value="6">(2) - Value 6</option>
<option filter="2" value="7">(2) - Value 7</option>
<option filter="3" value="8">(3) - Value 8</option>
<option filter="3" value="9">(3) - Value 9</option>
<option filter="3" value="10">(3) - Value 10</option>
</select>
JavaScript
$.filterSelect = {
config: {
target: "",
//if target = "" then only the beforeChange, afterChange and backChaining are executed
targetAttribute: "filter",
//attribute to filter on
defaultValue: "selector",
hideDefault: true,
//if true, removes the default selector when it is deselected
backChaining: false,
//if true filters back up the heirachy, must call filterSelect({backChaining: true}) after the call targeting the last select
backTarget: "",
onBeforeChange: null,
//function of the form (change event, target element)
onAfterChange: null,
//function of the form (change event, target element)
originalOptions: null
}
};
$.fn.filterSelect = function(config) {
//last argument is for backChaining
config = $.extend({}, $.filterSelect.config, config, $(this).data("filterSelect"));
$(this).data("filterSelect", config);
if (config.backChaining && config.target !== "") $(config.target).data("filterSelect", $.extend({}, $(config.target).data("filterSelect"), {
backTarget: $(this)
}));
$(this).change(function(event) {
var config = $(this).data("filterSelect");
if (config.originalOptions === null && config.target != "") {
config.originalOptions = $(config.target + " option")
}; //set the original options
if (config.onBeforeChange && config.onBeforeChange.call($(this), event, $(config.target)) === false) {
return this;
} //stops the change occuring, say if invalid change
if ($(config.target + " option[" + config.targetAttribute + "!=" + $(this).val() + "]").length > 0 && config.target != "") { //if == 0, already filtered
var currentVal = $(config.target).val();
if ($(this).val() == config.defaultValue) {
$(config.target).html("").prepend($(config.originalOptions).clone()).val(currentVal);
} else...