如何修改这个jQuery,使得下拉菜单中的选项动态显示和隐藏?

4
在这个示例中,我有一系列3个下拉选择框。每个都应用了相同的类(“group-1”),以表明它们是相关的(并允许在同一页上有多个选择组)。将“data-parent”属性应用于select以建立1:1的父/子关系。将“data-parent”属性应用于option以建立多对多的关系。
我的目标是创建一个动态的jQuery代码片段,以便我不必通过id或class显式地识别行为,而是通过选项值和数据父级值来实现。
我的问题:
1.第三个下拉菜单根本没有更新。我以为可能是因为其中一些具有多个data-parent值(用空格分隔),但即使我将它们全部更改为只有一个,它仍然不会随第二个下拉菜单的更改而更新。
2.我不确定如何在第三个下拉菜单的选项中实现“many”data-parent值。拆分字符串,创建数组,并检查该值是否在数组中?
3.当我更改父级下拉菜单时,如何将第二和第三个下拉菜单重置为“默认”值?例如,如果我从第一个选择“Cookies”,则“1 dozen”和“2 dozen”将显示在第二个下拉菜单中。但是,如果我选择“1 dozen”,然后将第一个框更改为“Cakes”,则“1 dozen”仍然被选中,即使在下拉菜单中只有“Sheet”和“Round”可用选项。我想将其重置为默认值(“Desserts …”)。
以下是代码,并且这是我的工作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>

感谢您提前提供的所有帮助!也欢迎提出改进建议。

2个回答

1
我不知道这段代码的背景,所以不清楚这种“嵌套”选项和选择是否是最佳解决方案。但这里是我的 JavaScript 版本,似乎实现了问题的要求。我会注释相关更改,以便清晰地了解我的思路。我还添加了一个隐藏类的 CSS,因为它不在 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://dev59.com/uHM_5IYBdhLWcg3wWRuV#16598989 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;
}

我不确定是否过度使用了注释,如果有任何不清楚的地方,请随意发表评论。


太完美了!我刚刚进行了一个快速测试,添加了更多“链接”的下拉菜单,以及其他一些选择框组合,它正如我所设想的那样工作。谢谢! - penteratap

1
您可以使用attributeContainsWord (~)来匹配多个值与一个单词。因此,在下面的代码中,我使用了$(this).children("option[data-parent~='" + selVal + "']").show();来显示与selVal匹配的选项。此外,我使用了prop('selectedIndex', 0);将选择重置为默认值。

演示代码:

$(document).ready(function() {
  $(".hide").children("option").hide();
  $("select").on('change', function() {
    //checking if dropdown is categories
    if ($(this).attr("name") == "categories") {
      //reset other to default
      $('select[name=desserts]').prop('selectedIndex', 0);
      $('select[name=flavors]').prop('selectedIndex', 0);
    }

    var selClass = $(this).attr("class");
    var selName = $(this).attr("name");
    var selVal = $(this).children("option:selected").val();
    //check if name != desserts
    if ($(this).attr("name") != "desserts") {
      //hide option of flavour
      $("select[name=flavors]").children("option").hide();
      //loop and show desire values
      $("select." + selClass + "[data-parent='" + selName + "']").each(function() {
        $(this).children("option[data-parent='" + selVal + "']").show();
        $(this).children("option[data-parent!='" + selVal + "']").hide();
      });

    } else {
      //hide options
      $("select[name=flavors]").children("option").hide();
      //loop through flavours
      $("select[name=flavors]").each(function() {
        //use " ~ " to see if the selval matches with values 
        $(this).children("option[data-parent~='" + selVal + "']").show();

      });

    }
  });
});
<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>


这个解决方案的问题是我试图避免在JavaScript中使用特定的标识符,因为页面上会有6或7个“组”。我希望使用“group-#”类和data-parent属性在页面上创建关系,让JS具有动态性。 - penteratap

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接