Issue
In this example, I have a series of 3 select drop-downs. The same class ("group-1") is applied to each to indicate that they are related (and to allow for multiple select groups on the same page). The "data-parent" attribute is applied to the select to establish a 1:1 parent/child relationship. The "data-parent" attribute is applied to the option to establish a many:many relationship.
My goal is to create a piece of dynamic jQuery code so that I don't have to explicitly identify behavior by id or class, but rather by option value and data-parent value.
My issues:
- The third drop-down doesn't update at all. I thought it might be that some of them have more than one data-parent value (separated by a space), but even if I change them to all have just one, it still doesn't update with changes to the second drop-down.
- I'm not sure how to implement the "many" data-parent values in the options for the third drop-down. Split the string, create an array, and check to see if the value is in the array?
- How do I reset the second and third drop-downs to the "default" value with a change to the parent drop-down? For example, if I choose "Cookies" from the first, "1 dozen" and "2 dozen" show up in the second. But if I select "1 dozen" and then change the first box to "Cakes", "1 dozen" remains selected even though "Sheet" and "Round" are the only available options in the drop-down. I'd like for it to reset to the default ("Desserts...").
Code is below, and here's my working jsfiddle: https://jsfiddle.net/rwh4z623/20/
$(document).ready(function(){
$(".hide").children("option").hide();
$("select").on('change', function(){
var selClass = $(this).attr("class");
var selName = $(this).attr("name");
var selVal = $(this).children("option:selected").val();
$("select."+selClass+"[data-parent='"+selName+"']").each(function(){
$(this).children("option[data-parent='"+selVal+"']").show();
$(this).children("option[data-parent!='"+selVal+"']").hide();
});
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select class="group-1" name="categories">
<option value="" selected="selected">Please select...</option>
<option value="cookie">Cookies</option>
<option value="cake">Cakes</option>
<option value="icecream">Ice Cream</option>
</select>
<select class="group-1 hide" name="desserts" data-parent="categories">
<option value="" selected="selected">Desserts...</option>
<option value="1-dozen" data-parent="cookie">1 dozen</option>
<option value="2-dozen" data-parent="cookie">2 dozen</option>
<option value="sheet" data-parent="cake">Sheet</option>
<option value="round" data-parent="cake">Round</option>
<option value="pint" data-parent="icecream">Pint</option>
</select>
<select class="group-1 hide" name="flavors" data-parent="desserts">
<option value="" selected="selected">Flavors...</option>
<option value="choc-chip" data-parent="1-dozen 2-dozen">Chocolate Chip</option>
<option value="oatmeal" data-parent="1-dozen 2-dozen">Oatmeal</option>
<option value="yellow" data-parent="sheet round">Yellow</option>
<option value="red-velvet" data-parent="sheet">Red Velvet</option>
</select>
Thanks in advance for any and all help! Also, suggestions on improvements are appreciated.
Solution
I don't know the context of this code so I have no idea, if this pattern of "nested" options and selects is the best solution. But here is my version of the javascript that seems to achieve what was asked in the question. I'll comment the relevant changes so my thought process is clear. I also added the css for a hide class, as that wasn't in the jsfiddle.
$(document).ready(function () {
$("select").on('change', function () {
var selClass = $(this).attr("class");
var selName = $(this).attr("name");
var selVal = $(this).children("option:selected").val();
//Call the update function with the data of the changed Select
updateRecursivly(selClass, selName, selVal);
//Recursive function to update all selects, this allows for multiple "child" selects per select and an in theory infinite "tree" of selects
function updateRecursivly(selClass, selName, selVal) {
//Search "children" of the parent select
var children = $("select." + selClass + "[data-parent='" + selName + "']");
if (children.length) {
children.each(function () {
//Hide all options in the "child" select
$(this).children("option[data-parent]").hide();
//if selVal is an empty string, the default option is selected and we should just hide the "child" select
if (selVal !== "") {
//Get all options that contain (*=) selVal in "data-parent"
var options = $(this).children("option[data-parent*='" + selVal + "']");
//If there are possible options show the select and the possible options. Else hide select
if (options.length) {
$(this).removeClass('hide');
options.show();
} else {
$(this).addClass('hide');
}
} else {
$(this).addClass('hide');
}
//If the select is updated, the options should be reset. Any selected is reset and the first is selected
//From here https://stackoverflow.com/a/16598989/14040328 this is apparently safer against reset events than other solutions
$(this).children("option:selected").prop("selected", false);
$(this).children("option:first").prop("selected", "selected");
//Get the name of the select
var childName = $(this).attr("name");
//Update the Child select
updateRecursivly(selClass, childName, "");
});
}
}
});
});
.hide {
display: none;
}
I'm not sure if I overdid the comments or not, if anything is unclear feel free to comment.
Answered By - user14040328
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.