根据某些选择JavaScript禁用下拉列表中的选项



因此,当在相邻的下拉列表中进行某个选择时,我试图将某些日期禁用。我有20对这些下拉菜单。当它只有1对,但两者兼而有之时,我可以使它起作用。因此,当选择"月1"时,我需要" 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 Loop时,选择菜单和选项也不会加载。因此,您应该使用Domcontentloaded事件(要遵循的代码(将主循环包装为循环,以确保仅在加载DOM之后运行。如果您使用的是jQuery u可以将整个内容包裹在$(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(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')

当它最终运行了这一点代码时,它在当前时间获得x的值,在for循环完成之后,这意味着其值为 21。在循环完成后,它可以访问x值,因为,正如我们所讨论的那样,该变量没有范围范围范围内,它存在于其外部。因此,对于此事件的所有呼叫,x将为21,无论您选择哪个下拉菜单。由于21不是有效日名的一部分,因此数组将始终为空。

解决方案是将更改事件调用包装在其自己的函数中,并将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个陆路,其中一个是嵌套的,每次在20个下拉列中选择一个月时,每个月都会选择一个月。无需这样做,您应该在加载DOM时一次禁用一次相关选项,而不必在更改事件中循环循环。您必须考虑数据的状态和改变数据的事件;选择一个月下拉列表对残疾天对象没有影响,因此您不必更新任何依赖此数据的元素。

最新更新