[英]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.