如何防止事件监听器触发多个下拉菜单?

问题描述 投票:0回答:1

当我与多复选框下拉菜单交互时,我尝试通过触发 AJAX 请求来使用后端 Flask 服务器获取数据。本质上,我有两个下拉菜单,分别称为“选择日期”和“选择频道”。 “选择日期”下拉菜单对应于特定的 .parquet 文件,“选择频道”对应于这些 .parquet 文件的列标题。

但是,当我与其中一个下拉菜单交互时,另一个下拉菜单的事件也会被触发(甚至不与其交互)。我该如何避免这种情况?

我有以下 JS 脚本用于创建 MultiCheckbox 下拉菜单,我已将其另存为 select-checkbox.js:

        $(document).ready(function () {
            $(document).on("click", ".MultiCheckBox", function () {
                var detail = $(this).next();
                detail.show();
            });

            $(document).on("click", ".MultiCheckBoxDetailHeader input", function (e) {
                e.stopPropagation();
                var hc = $(this).prop("checked");
                $(this).closest(".MultiCheckBoxDetail").find(".MultiCheckBoxDetailBody input").prop("checked", hc);
                $(this).closest(".MultiCheckBoxDetail").next().UpdateSelect();
            });

            $(document).on("click", ".MultiCheckBoxDetailHeader", function (e) {
                var inp = $(this).find("input");
                var chk = inp.prop("checked");
                inp.prop("checked", !chk);
                $(this).closest(".MultiCheckBoxDetail").find(".MultiCheckBoxDetailBody input").prop("checked", !chk);
                $(this).closest(".MultiCheckBoxDetail").next().UpdateSelect();
            });

            $(document).on("click", ".MultiCheckBoxDetail .cont input", function (e) {
                e.stopPropagation();
                $(this).closest(".MultiCheckBoxDetail").next().UpdateSelect();

                var val = ($(".MultiCheckBoxDetailBody input:checked").length == $(".MultiCheckBoxDetailBody input").length)
                $(".MultiCheckBoxDetailHeader input").prop("checked", val);
            });

            $(document).on("click", ".MultiCheckBoxDetail .cont", function (e) {
                var inp = $(this).find("input");
                var chk = inp.prop("checked");
                inp.prop("checked", !chk);

                var multiCheckBoxDetail = $(this).closest(".MultiCheckBoxDetail");
                var multiCheckBoxDetailBody = $(this).closest(".MultiCheckBoxDetailBody");
                multiCheckBoxDetail.next().UpdateSelect();

                var val = ($(".MultiCheckBoxDetailBody input:checked").length == $(".MultiCheckBoxDetailBody input").length)
                $(".MultiCheckBoxDetailHeader input").prop("checked", val);
            });

            $(document).mouseup(function (e) {
                var container = $(".MultiCheckBoxDetail");
                if (!container.is(e.target) && container.has(e.target).length === 0) {
                    container.hide();
                }
            });
        });

        var defaultMultiCheckBoxOption = { width: '220px', defaultText: 'Select Below', height: '200px' };

        jQuery.fn.extend({
            CreateMultiCheckBox: function (options) {
                    

                var localOption = {};
                localOption.width = (options != null && options.width != null && options.width != undefined) ? options.width : defaultMultiCheckBoxOption.width;
                localOption.defaultText = (options != null && options.defaultText != null && options.defaultText != undefined) ? options.defaultText : defaultMultiCheckBoxOption.defaultText;
                localOption.height = (options != null && options.height != null && options.height != undefined) ? options.height : defaultMultiCheckBoxOption.height;
                
                this.hide();
                this.attr("multiple", "multiple");
                var divSel = $("<div class='MultiCheckBox'>" + localOption.defaultText + "<span class='k-icon k-i-arrow-60-down'><svg aria-hidden='true' focusable='false' data-prefix='fas' data-icon='sort-down' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 512' class='svg-inline--fa fa-sort-down fa-w-10 fa-2x'><path fill='currentColor' d='M41 288h238c21.4 0 32.1 25.9 17 41L177 448c-9.4 9.4-24.6 9.4-33.9 0L24 329c-15.1-15.1-4.4-41 17-41z' class=''></path></svg></span></div>").insertBefore(this);
                divSel.css({ "width": localOption.width });

                var detail = $("<div class='MultiCheckBoxDetail'><div class='MultiCheckBoxDetailHeader'><input type='checkbox' class='mulinput' value='-1982' /><div>Select All</div></div><div class='MultiCheckBoxDetailBody'></div></div>").insertAfter(divSel);
                detail.css({ "width": parseInt(options.width) + 10, "max-height": localOption.height });
                var multiCheckBoxDetailBody = detail.find(".MultiCheckBoxDetailBody");


                this.find("option").each(function () {
                    var val = $(this).attr("value");

                    if (val == undefined)
                        val = '';

                    multiCheckBoxDetailBody.append("<div class='cont'><div><input type='checkbox' class='mulinput' value='" + val + "' /></div><div>" + $(this).text() + "</div></div>");
                });

                multiCheckBoxDetailBody.css("max-height", (parseInt($(".MultiCheckBoxDetail").css("max-height")) - 28) + "px");

            },
            UpdateSelect: function () {
                var arr = [];

                this.prev().find(".mulinput:checked").each(function () {
                    arr.push($(this).val());
                });

                this.val(arr);
            },
        });`

在 HTML 方面,我通过以下方式创建了两个名为“选择频道”和“选择日期”的下拉菜单:

<head>
    <script>
        $(document).ready(function () {
            $("#test").CreateMultiCheckBox({ width: '230px', defaultText : 'Select Below', height:'250px' });
        });
    </script>
        <script>
        $(document).ready(function () {
            $("#test_2").CreateMultiCheckBox({ width: '230px', defaultText : 'Select Below', height:'250px' });
        });
    </script>
</head>`
  <body>
  
    <div class="container">
      <div class="side-container">
        <!-- First Dropdown -->
      <div class="mb-3" data-dropdown-type="channel">
    <label for="exampleFormControlSelect1" class="form-label">Select Channel</label>
    <select id="test">
      {% for column in data %}
      <option value="{{ column }}">{{ column }}</option>
    {% endfor %}

    </select>

  </div>
  <!-- Second Dropdown -->

  <div class="mb-3" data-dropdown-type="date">
    <label for="exampleFormControlSelect1" class="form-label">Select Date</label>
    <select id="test_2">
      {% for parquet_file in parquet_files %}
      <option value="{{ parquet_file }}">{{ parquet_file }}</option>
    {% endfor %}
</select>
  </div>`

下拉菜单的选项是基于后端 Flask 服务器生成的。 现在,我尝试使用事件侦听器触发 Ajax 请求,以获取下拉菜单上所选选项的相应数据。我想从“选择日期”下拉菜单中获取所选数据的通道数据。但是,当我与其中一个下拉菜单交互时,即使不与其交互,我也会为另一个下拉菜单打印 console.log。我假设这是因为更改事件侦听器附加到整个文档(document.addEventListener(“change”,...))。这意味着每当文档中的任何位置发生任何更改事件(而不仅仅是在下拉列表中)时,都会触发事件侦听器。 我该如何解决? 以下是 fetchData 函数和发出 AJAX 请求的 JS 脚本:

 function fetchData(selectedChannels, selectedFiles) {
    console.log("Fetching data...");
    console.log(selectedChannels)
    console.log(selectedFiles)
    // Make an AJAX request to the backend with selectedChannel and selectedFile
    $.ajax({
      url: "/fetch_data",
      type: "POST",
      data: JSON.stringify({ channels: selectedChannels, files: selectedFiles }),
      contentType: "application/json",
      success: function (response) {
        console.log("Data received successfully:", response);
        // Render the data received from the backend on the webpage
        displayData(response);
      },
      error: function(xhr, status, error) {
        console.error("Error fetching data:", error);
      },
    });
  }


  // Function to display the data on the webpage
  function displayData(data) {
    // You can update the DOM elements with the data received
    // For example, create tables or charts to visualize the data
    console.log(data);
  }

这是事件监听器:

  document.addEventListener("change", function (event) {
      const target = event.target;
      console.log("Event triggered.")
      console.log(target)

      var array = []
      $("#test option").each(function(){
                        if($(this).is(":selected"))
                        {array.push($(this).val());}  
                    }); 
      console.log(array)
      var array1 = []      
      $("#test_2 option").each(function(){
                        if($(this).is(":selected"))
                        {array1.push($(this).val());}    
                    }); 
      console.log(array1)
      if (array.length >=1 && array1.length>=1) {
        const selectedChannels = Array.from(array)//.map(checkbox => checkbox.value);
        console.log(selectedChannels)
        const selectedFiles = Array.from(array1)//.map(checkbox => checkbox.value);
        console.log(selectedFiles)
        fetchData(selectedChannels,selectedFiles);
        
      }
      else{
        console.log("No match found")
      }
    });

  </script>
javascript html ajax flask event-listener
1个回答
0
投票

将事件监听器直接注册到选择元素。

<script>
    $(document).ready(function () {
        $("#test").CreateMultiCheckBox({ 
            defaultText: 'Select Below', 
            height:'250px', 
            width: '230px' 
        });
        $("#test_2").CreateMultiCheckBox({ 
            defaultText: 'Select Below', 
            height:'250px', 
            width: '230px' 
        });

        $('#test, #test_2').change(function(evt) {
            // Your listener code here!
        });
    });
</script>

事件可能不会被触发,因为您正在

UpdateSelect
中通过 JavaScript 更新选择元素。在这种情况下,当选择元素更新时手动触发事件。

const event = new Event('change');
selectElem.dispatchEvent(event);
© www.soinside.com 2019 - 2024. All rights reserved.