繁体   English   中英

根据某些选择,禁用下拉菜单中的选项

[英]disable options in drop down based on certain selections javascript

因此,当我在相邻下拉列表中进行某些选择时,我试图禁用某个下拉列表中的某些日期。 我有20对这些下拉菜单。 当只有一对时,我不能让它工作。 因此,当选择“ month1”时,我需要“ day1”中的某些选项不可用。

data = {
      disabled_days: {
        "June": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 17, 18, 24, 25, 31],
        "July": [1, 2, 3, 4, 8, 9, 15, 16, 22, 23, 29, 30],
        "August": [5, 6, 12, 13, 19, 20, 26, 27]
      }
    }
    //loop through to create this 20 times
    for(x=1;x<=20;x++){
    //get the select month box
    let select_month = document.querySelector('select[name="month'+x+'"]');

    //when month is selected
    select_month.addEventListener('change', function(e){

      //get the name of the month
      let month = select_month[select_month.selectedIndex].textContent;

      //get all the days in the data select box and enable them all
      let day_arr = [].slice.call(document.querySelectorAll('select[name="day'+x+'"] option'))
      for(let day of day_arr) day.disabled = false;

      //loop over all the days to be disabled, find thme in the data ovject based on month and disable those days
      for (let disabled_day of data.disabled_days[month]){
        for (let day of day_arr){
          if (day.textContent == disabled_day) day.disabled = true;
        }
      }
    })
  }

所以我认为我在串联的某个地方有问题('select[name="day'+x+'"] option')并且在月份中也一样。 现在已经把我搞砸了近一个星期,所以我们将不胜感激。

这是相关的php和html:

  <?php for($x=1; $x<=20; $x++){ ?>
              <div class="form-group">
                <label><?php echo "$x"; ?>.</label>
                <select class="form-control" name="month<?php echo $x ;?>">
                  <option selected disabled>- Month -</option>
                  <option value="06">June</option>
                  <option value="07">July</option>
                  <option value="08">August</option>
                </select>
                <select class="form-control" name="day<?php echo $x ;?>">
                  <option selected disabled>- Day -</option>
                  <option value="01">1</option>
                  <option value="02">2</option>
                  <option value="03">3</option>
                  <option value="04">4</option>
                  <option value="05">5</option>
                  <option value="06">6</option>
                  <option value="07">7</option>
                  <option value="08">8</option>
                  <option value="09">9</option>
                  <option value="10">10</option>
                  <option value="11">11</option>
                  <option value="12">12</option>
                  <option value="13">13</option>
                  <option value="14">14</option>
                  <option value="15">15</option>
                  <option value="16">16</option>
                  <option value="17">17</option>
                  <option value="18">18</option>
                  <option value="19">19</option>
                  <option value="20">20</option>
                  <option value="21">21</option>
                  <option value="22">22</option>
                  <option value="23">23</option>
                  <option value="24">24</option>
                  <option value="25">25</option>
                  <option value="26">26</option>
                  <option value="27">27</option>
                  <option value="28">28</option>
                  <option value="29">29</option>
                  <option value="30">30</option>
                  <option value="31">31</option>
                </select>
              </div> <?php } ?>

好的,因此有一些原因导致您无法正常使用下拉菜单时遇到问题:

首先,我注意到如果您提供的js代码保持原样,则以下调用将返回一个空数组:

let select_month = document.querySelector('select[name="month'+x+'"]');

对于您来说,这可能会有所变化,具体取决于您的浏览器呈现DOM和运行脚本的速度,但是通常来说,运行for循环时,不能保证选择菜单和选项会被加载。 因此,应使用DOMContentLoaded事件(后面的代码)包装main for循环,以确保它仅在DOM加载后运行。 如果您使用的是jQuery,则可以将整个内容包装在$(document).ready(...)函数中。

其次,您可以替换以下行:

let day_arr = [].slice.call(document.querySelectorAll('select[name="day'+x+'"] option'))

只是:

let day_arr = document.querySelectorAll('select[name="day'+idx+'"] option');

querySelectorAll已经返回一个可以迭代的数组。 您还会注意到,我有变量idx而不是x 那是由于第三个或更令人困惑的原因。

在javascript中用var声明的变量没有块作用域(可以在es6中使用let来避免这种情况),它们的作用域是它们在其中定义的函数,或者是全局作用域。 这意味着在您的主要for循环中: for(x=1;x<=20;x++)变量的范围未定义为位于for循环块内,就像使用c / c ++,java, c#,而是将其定义为对其进行封装的函数的范围。 在这种特殊情况下,没有包围它的函数,因此它属于全局对象。 因此,结果如下:

运行for循环时,它将遍历该块并执行所有代码,其中之一是注册此事件侦听器:

select_month.addEventListener('change', function(e){})

此事件侦听器是一个异步调用,这意味着它在运行for循环时不会执行,只能声明并注册到事件中。 这意味着当它最终运行时,在发生更改事件之后,for循环早已完成。 但是此更改事件函数在以下行中引用了x

document.querySelectorAll('select[name="day'+x+'"] option')

当它最终运行了这段代码时,它会在for循环完成之后很久之后的当前时间获取x的值,这意味着其值为21 循环完成后,它可以访问x值,因为如我们所讨论的,该变量的作用域不为for循环,而是存在于它之外。 因此,无论您选择哪个下拉列表,对该事件的所有调用x均为21 由于21不是有效日期名称的一部分,因此该数组将始终为空。

解决方案是将change事件调用包装在其自己的函数中,然后将x的值作为参数传递给此新函数,将其称为idx 此函数将立即声明并执行。 请注意,即使函数已运行,更改事件仍仅被注册而不执行。 现在,querySelector语句将引用函数参数而不是x变量。 由于函数参数是针对每个循环执行的,因此每次都会传入x的新值,因此对于每个更改事件侦听器,该参数也是新的。 您可能之前已经看过这种模式,它称为闭包。

我已经更新了您的代码,看看:

var data = {
  disabled_days: {
    "June": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 17, 18, 24, 25, 31],
    "July": [1, 2, 3, 4, 8, 9, 15, 16, 22, 23, 29, 30],
    "August": [5, 6, 12, 13, 19, 20, 26, 27]
  }
}
//On DOM Loaded
document.addEventListener("DOMContentLoaded", function(event) { 
    //loop through to create this 20 times
    for(x=1;x<=20;x++){
        //get the select month box
        let select_month = document.querySelector('select[name="month'+x+'"]');

        //A colusure to wrap the change event listener, this is done
        //to pass the current value of x into the listener
        (function(idx){
          //when month is selected
          select_month.addEventListener('change', function(e){

            //get the name of the month
            let month = select_month[select_month.selectedIndex].textContent;

            //get all the days in the data select box and enable them all
            let day_arr = document.querySelectorAll('select[name="day'+idx+'"] option');

            for(let day of day_arr) day.disabled = false;

            //loop over all the days to be disabled, find thme in the data ovject based on month and disable those days
            for (let disabled_day of data.disabled_days[month]){
                for (let day of day_arr){
                    if (day.textContent == disabled_day) day.disabled = true;
                }
            }    
          })
        })(x);
    }
});

最后,您应该真正重新考虑代码中的逻辑。 它有很多低效和不必要的部分,尤其是在事件侦听器中。 您当前正在调用2个for循环,其中一个嵌套,每次在20个下拉列表中的任何一个中选择每月一次。 不需要这样做,您应该在加载DOM时禁用一次相关选项,并且永远不必在change事件上循环。 您必须考虑数据的状态以及更改数据的事件; 选择月份下拉列表对禁用日期对象没有影响,因此您不必更新依赖此数据的任何元素。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM