如何确定数组中的值是否位于两个附加数组的所有平行索引处的值之间?
How can I determine if value from array lies between values at all parallel indices of two additional arrays?
我有四个数组,具有以下作用:
- 所有现有的开始日期(未选中)
- 所有现有的结束日期(未选中)
- 所选项目的开始日期(选中)
- 所选项目的结束日期(选中)
1 和 2 包含集合中所有未selected 事件的开始和结束时间戳池。
当与事件关联的复选框被选中时,3 和 4 填充有开始和结束时间戳,当它们未被选中时,时间戳被删除。
结果应该是,如果未selected 项目的日期范围与新 selected 项目的日期范围冲突,则阻止它们被 selected 并直观地显示它们是禁用选项。
我目前将所有未检查项目的值与比较数组中的最近检查日期进行比较,但它忽略了之前的那些。这意味着我可能 select 一个,冲突的日期被禁用,但是当我 select 另一个可用选项时,以前禁用的那些被重新启用。
我不是 100% 确定如何确保将所有未选中的项目与所有已选中的项目进行比较,并根据日期是否冲突将其禁用。在现有循环中添加嵌套 for 循环是否是解决此问题的最佳方法?
P.S。我知道有一些奇怪的 select 或额外的工作来格式化日期,但我这样做的人坚持认为日期格式是 MON ## - ##(同一个月)和 MON ## - MON ##(不同月份)和日期包含在复选框标签中的小标签中。
var camp_dates;
var camp_start;
var camp_end;
var other_camp_dates;
var other_camp_start;
var other_camp_end;
var checked_start = [];
var checked_end = [];
var year = new Date().getFullYear();
// Change checkbox apply filters
$("#gform_11 input[type=checkbox]").click(function(){
//Reset list of checked items
checked_start = [];
checked_end = [];
camp_dates = $("label[for='" + $(this).attr("id") + "'] small").html().split("-");
camp_start = camp_dates[0].split(" ");
camp_end = camp_dates[1].split(" ");
//If no month in end date, assume same month as first (Ex. Jul 06-22 == Jul 06 - Jul 22)
if (camp_end.length == 1){
camp_end.unshift(camp_start[0]);
}
//rejoin day and months, add year to parse for timestamp
camp_start = Date.parse(camp_start.join(" ") + ", " + year);
camp_end = Date.parse(camp_end.join(" ") + ", " + year);
//Take empty start and arrays and add dates for selections
$(".gfield_checkbox input:checked").each(function(){
//All currently checked items
checked_start.push(camp_start);
checked_end.push(camp_end);
});
$(".gfield_checkbox input:not(:checked) + label small").each(function(){
//Gen values for all unselected items
other_camp_dates = $(this).html().split("-");
other_camp_start = other_camp_dates[0].split(" ");
other_camp_end = other_camp_dates[1].split(" ");
//If no month in end date, assume same month as first
if (other_camp_end.length == 1){
other_camp_end.unshift(other_camp_start[0]);
}
//rejoin day and months, add year to parse for timestamp
other_camp_start = Date.parse(other_camp_start.join(" ") + ", " + year);
other_camp_end = Date.parse(other_camp_end.join(" ") + ", " + year);
// Loop through arrays of start/end dates and compare to each unselected item - apply fade, disable, color
var i;
for (i = 0; i < checked_start.length; i++) {
if ( other_camp_start >= checked_start[i] && other_camp_start < checked_end[i] ||
other_camp_end > checked_start[i] && other_camp_end <= checked_end[i] ){
// If there is conflict
$(this).css("color", "red").parent().fadeTo("slow",0.5).siblings("input").not(":checked").attr("disabled", true);
} else {
$(this).css("color", "#7E7E7E").parent().fadeTo("slow",1).siblings("input").attr("disabled", false);
}
}
});
});
您似乎在启用/禁用复选框的方式上遇到了问题。您正在遍历每个未选择的项目,如果它们与选定的项目冲突,则禁用它们,如果不冲突,则启用它们。
这就是问题所在:假设您有一个未检查的日期与已检查的日期冲突。您禁用未选中的那个。
但是在循环的后面,当你和另一个检查它并且没有冲突时,你重新启用它。如果它在循环中的某处被禁用,它应该保持禁用状态。
另一个问题:在您发表评论“//Take empty start and arrays and add dates for selections
”的地方,您一遍又一遍地推送相同的值(camp_start
和 camp_end
)而没有获取每个选定的日期。
这是修改后的版本:
jQuery(document).ready(function($){
var camp_dates,
other_camp_dates,
checked_dates = [],
year = new Date().getFullYear();
// Change checkbox apply filters
$("#gform_11 input[type=checkbox]").click(function(){
//Reset list of checked items
checked_dates = [];
camp_dates = formatDates( $("label[for='" + $(this).attr("id") + "'] small").html() );
//Take empty checked_dates and add dates for selections
$(".gfield_checkbox input:checked + label small").each(function(){
//All currently checked items
checked_dates.push( formatDates( $(this).html() ) );
});
// For each unchecked item
$(".gfield_checkbox input:not(:checked) + label small").each(function(){
//Get the dates
other_camp_dates = formatDates( $(this).html() );
// Enable the checkbox before matching it with all checked_dates
// If we don't do that now, imagine we have a date that conflicts (we disable it),
// and the next one does not conflict : we reenable it. Not what we want.
$(this).css("color", "#7E7E7E").parent().css("opacity",1).siblings("input").attr("disabled", false);
// Loop through arrays of checked_dates and compare to the current unchecked item
var i, l = checked_dates.length;
for (i = 0; i<l; i++) {
if ( other_camp_dates.start >= checked_dates[i].start && other_camp_dates.start < checked_dates[i].end ||
other_camp_dates.end > checked_dates[i].start && other_camp_dates.end <= checked_dates[i].end ){
//Conflict
$(this).css("color", "red").parent().css("opacity",.5).siblings("input").not(":checked").attr("disabled", true);
}
// If there is no conflict for this one, there may be one for a previous one,
// so we don't enable it here
}
});
});
// It's messy enough to make it a function and not rewrite it
function formatDates(str){
var dates = str.split("-"),
start_date = dates[0].split(" "),
end_date = dates[1].split(" ");
if (end_date.length == 1){
end_date.unshift(start_date[0]);
}
start_date = Date.parse(start_date.join(" ") + ", " + year);
end_date = Date.parse(end_date.join(" ") + ", " + year);
return {
"start" : start_date,
"end" : end_date
};
}
}); // jQuery(document).ready
如果我没理解错的话,这比代码暗示的要简单。
首先,可以通过编写一个parseDates()
函数来消除用于解析日期的重复代码,其中:
- returns 具有
.start
和 .end
属性的对象。
- 可以用作
.map()
回调,一次用于选中复选框,一次用于未选中复选框。
然后,剩下要做的就是在嵌套循环中检查所有未检查的日期与所有已检查的日期,并管理未检查项目的禁用状态。这样做的一个主要因素是仅当所有禁用的项目都已知时才重新启用项目 - 即在两个嵌套循环完成后。
代码应该是这样的:
// Change checkbox apply filters
$("#gform_11 input[type=checkbox]").click(function(){
var year = new Date().getFullYear();
//A utility function for parsing out start and end dates
function parseDates() {
var dates = $(this).html().split("-"),
start = dates[0].split(" "),
end = dates[1].split(" ");
//If no month in end date, assume same month as first (Ex. Jul 06-22 == Jul 06 - Jul 22)
if (end.length == 1) {
end.unshift(start[0]);
}
//return an object with .start and .end properties
return {
start: Date.parse(start.join(" ") + ", " + year), //rejoin
end: Date.parse(end.join(" ") + ", " + year) //rejoin
};
}
//A utility function for comparing a checked date with an unchecked date
function compareDateRanges(checked, unchecked) {
return ( unchecked.start >= checked.start && unchecked.start < checked.end ) ||
( unchecked.end > checked.start && unchecked.end <= checked.end )
}
var $checked = $(".gfield_checkbox input:checked");
var $unchecked = $(".gfield_checkbox input:not(:checked)").removeClass('disabled');
var checkedDates = $checked.siblings("label").find("small").map(parseDates).get();//make array of start-end objects for checked inputs
var uncheckedDates = $unchecked.siblings("label").find("small").map(parseDates).get();//make array of start-end objects for unchecked inputs
for(var i=0; i<checkedDates.length; i++) {
for(var j=0; j<uncheckedDates.length; j++) {
if(compareDateRanges(checkedDates[i], uncheckedDates[j])) {
// If there is conflict
$unchecked.eq(j).addClass('disabled').attr('disabled', true).siblings("label").find("small").css('color', 'red').parent().fadeTo('slow', 0.5);
}
}
}
//when all disabled elements are known, all others can be eneabled.
$unchecked.not(".disabled").attr('disabled', false).siblings("label").find("small").css('color', '#7E7E7E').parent().fadeTo('slow', 1);
});
编辑 1
为了满足可能跨越新一年的日期范围:
//A utility function for parsing out start and end dates
function parseDates() {
var dates = $(this).siblings("label").find("small").html().split("-"),
start = dates[0].split(" "),
end = dates[1].split(" ");
//If no month in end date, assume same month as first (Ex. Jul 06-22 == Jul 06 - Jul 22)
if (end.length == 1) {
end.unshift(start[0]);
}
var obj = {
start: Date.parse(start.join(" ") + ", " + year), //rejoin
end: Date.parse(end.join(" ") + ", " + year) //rejoin
}
// Test for the date range spanning a New Year.
// If necessary, reparse `end` with next year's date
if(obj.end < obj.start) {
obj.end = Date.parse(end.join(" ") + ", " + (year + 1));
}
//return an object with .start and .end properties
return obj;
}
编辑 2
要在页面加载时执行,触发第一个复选框的点击处理程序:
$("#gform_11 input[type=checkbox]").click(function() {
... ...
}).eq(0).triggerHandler('click');
第一个复选框是否被选中并不重要,因为无论元素的 :checked 状态如何,所有内容都会一直计算。
我有四个数组,具有以下作用:
- 所有现有的开始日期(未选中)
- 所有现有的结束日期(未选中)
- 所选项目的开始日期(选中)
- 所选项目的结束日期(选中)
1 和 2 包含集合中所有未selected 事件的开始和结束时间戳池。
当与事件关联的复选框被选中时,3 和 4 填充有开始和结束时间戳,当它们未被选中时,时间戳被删除。
结果应该是,如果未selected 项目的日期范围与新 selected 项目的日期范围冲突,则阻止它们被 selected 并直观地显示它们是禁用选项。
我目前将所有未检查项目的值与比较数组中的最近检查日期进行比较,但它忽略了之前的那些。这意味着我可能 select 一个,冲突的日期被禁用,但是当我 select 另一个可用选项时,以前禁用的那些被重新启用。
我不是 100% 确定如何确保将所有未选中的项目与所有已选中的项目进行比较,并根据日期是否冲突将其禁用。在现有循环中添加嵌套 for 循环是否是解决此问题的最佳方法?
P.S。我知道有一些奇怪的 select 或额外的工作来格式化日期,但我这样做的人坚持认为日期格式是 MON ## - ##(同一个月)和 MON ## - MON ##(不同月份)和日期包含在复选框标签中的小标签中。
var camp_dates;
var camp_start;
var camp_end;
var other_camp_dates;
var other_camp_start;
var other_camp_end;
var checked_start = [];
var checked_end = [];
var year = new Date().getFullYear();
// Change checkbox apply filters
$("#gform_11 input[type=checkbox]").click(function(){
//Reset list of checked items
checked_start = [];
checked_end = [];
camp_dates = $("label[for='" + $(this).attr("id") + "'] small").html().split("-");
camp_start = camp_dates[0].split(" ");
camp_end = camp_dates[1].split(" ");
//If no month in end date, assume same month as first (Ex. Jul 06-22 == Jul 06 - Jul 22)
if (camp_end.length == 1){
camp_end.unshift(camp_start[0]);
}
//rejoin day and months, add year to parse for timestamp
camp_start = Date.parse(camp_start.join(" ") + ", " + year);
camp_end = Date.parse(camp_end.join(" ") + ", " + year);
//Take empty start and arrays and add dates for selections
$(".gfield_checkbox input:checked").each(function(){
//All currently checked items
checked_start.push(camp_start);
checked_end.push(camp_end);
});
$(".gfield_checkbox input:not(:checked) + label small").each(function(){
//Gen values for all unselected items
other_camp_dates = $(this).html().split("-");
other_camp_start = other_camp_dates[0].split(" ");
other_camp_end = other_camp_dates[1].split(" ");
//If no month in end date, assume same month as first
if (other_camp_end.length == 1){
other_camp_end.unshift(other_camp_start[0]);
}
//rejoin day and months, add year to parse for timestamp
other_camp_start = Date.parse(other_camp_start.join(" ") + ", " + year);
other_camp_end = Date.parse(other_camp_end.join(" ") + ", " + year);
// Loop through arrays of start/end dates and compare to each unselected item - apply fade, disable, color
var i;
for (i = 0; i < checked_start.length; i++) {
if ( other_camp_start >= checked_start[i] && other_camp_start < checked_end[i] ||
other_camp_end > checked_start[i] && other_camp_end <= checked_end[i] ){
// If there is conflict
$(this).css("color", "red").parent().fadeTo("slow",0.5).siblings("input").not(":checked").attr("disabled", true);
} else {
$(this).css("color", "#7E7E7E").parent().fadeTo("slow",1).siblings("input").attr("disabled", false);
}
}
});
});
您似乎在启用/禁用复选框的方式上遇到了问题。您正在遍历每个未选择的项目,如果它们与选定的项目冲突,则禁用它们,如果不冲突,则启用它们。
这就是问题所在:假设您有一个未检查的日期与已检查的日期冲突。您禁用未选中的那个。
但是在循环的后面,当你和另一个检查它并且没有冲突时,你重新启用它。如果它在循环中的某处被禁用,它应该保持禁用状态。
另一个问题:在您发表评论“//Take empty start and arrays and add dates for selections
”的地方,您一遍又一遍地推送相同的值(camp_start
和 camp_end
)而没有获取每个选定的日期。
这是修改后的版本:
jQuery(document).ready(function($){
var camp_dates,
other_camp_dates,
checked_dates = [],
year = new Date().getFullYear();
// Change checkbox apply filters
$("#gform_11 input[type=checkbox]").click(function(){
//Reset list of checked items
checked_dates = [];
camp_dates = formatDates( $("label[for='" + $(this).attr("id") + "'] small").html() );
//Take empty checked_dates and add dates for selections
$(".gfield_checkbox input:checked + label small").each(function(){
//All currently checked items
checked_dates.push( formatDates( $(this).html() ) );
});
// For each unchecked item
$(".gfield_checkbox input:not(:checked) + label small").each(function(){
//Get the dates
other_camp_dates = formatDates( $(this).html() );
// Enable the checkbox before matching it with all checked_dates
// If we don't do that now, imagine we have a date that conflicts (we disable it),
// and the next one does not conflict : we reenable it. Not what we want.
$(this).css("color", "#7E7E7E").parent().css("opacity",1).siblings("input").attr("disabled", false);
// Loop through arrays of checked_dates and compare to the current unchecked item
var i, l = checked_dates.length;
for (i = 0; i<l; i++) {
if ( other_camp_dates.start >= checked_dates[i].start && other_camp_dates.start < checked_dates[i].end ||
other_camp_dates.end > checked_dates[i].start && other_camp_dates.end <= checked_dates[i].end ){
//Conflict
$(this).css("color", "red").parent().css("opacity",.5).siblings("input").not(":checked").attr("disabled", true);
}
// If there is no conflict for this one, there may be one for a previous one,
// so we don't enable it here
}
});
});
// It's messy enough to make it a function and not rewrite it
function formatDates(str){
var dates = str.split("-"),
start_date = dates[0].split(" "),
end_date = dates[1].split(" ");
if (end_date.length == 1){
end_date.unshift(start_date[0]);
}
start_date = Date.parse(start_date.join(" ") + ", " + year);
end_date = Date.parse(end_date.join(" ") + ", " + year);
return {
"start" : start_date,
"end" : end_date
};
}
}); // jQuery(document).ready
如果我没理解错的话,这比代码暗示的要简单。
首先,可以通过编写一个parseDates()
函数来消除用于解析日期的重复代码,其中:
- returns 具有
.start
和.end
属性的对象。 - 可以用作
.map()
回调,一次用于选中复选框,一次用于未选中复选框。
然后,剩下要做的就是在嵌套循环中检查所有未检查的日期与所有已检查的日期,并管理未检查项目的禁用状态。这样做的一个主要因素是仅当所有禁用的项目都已知时才重新启用项目 - 即在两个嵌套循环完成后。
代码应该是这样的:
// Change checkbox apply filters
$("#gform_11 input[type=checkbox]").click(function(){
var year = new Date().getFullYear();
//A utility function for parsing out start and end dates
function parseDates() {
var dates = $(this).html().split("-"),
start = dates[0].split(" "),
end = dates[1].split(" ");
//If no month in end date, assume same month as first (Ex. Jul 06-22 == Jul 06 - Jul 22)
if (end.length == 1) {
end.unshift(start[0]);
}
//return an object with .start and .end properties
return {
start: Date.parse(start.join(" ") + ", " + year), //rejoin
end: Date.parse(end.join(" ") + ", " + year) //rejoin
};
}
//A utility function for comparing a checked date with an unchecked date
function compareDateRanges(checked, unchecked) {
return ( unchecked.start >= checked.start && unchecked.start < checked.end ) ||
( unchecked.end > checked.start && unchecked.end <= checked.end )
}
var $checked = $(".gfield_checkbox input:checked");
var $unchecked = $(".gfield_checkbox input:not(:checked)").removeClass('disabled');
var checkedDates = $checked.siblings("label").find("small").map(parseDates).get();//make array of start-end objects for checked inputs
var uncheckedDates = $unchecked.siblings("label").find("small").map(parseDates).get();//make array of start-end objects for unchecked inputs
for(var i=0; i<checkedDates.length; i++) {
for(var j=0; j<uncheckedDates.length; j++) {
if(compareDateRanges(checkedDates[i], uncheckedDates[j])) {
// If there is conflict
$unchecked.eq(j).addClass('disabled').attr('disabled', true).siblings("label").find("small").css('color', 'red').parent().fadeTo('slow', 0.5);
}
}
}
//when all disabled elements are known, all others can be eneabled.
$unchecked.not(".disabled").attr('disabled', false).siblings("label").find("small").css('color', '#7E7E7E').parent().fadeTo('slow', 1);
});
编辑 1
为了满足可能跨越新一年的日期范围:
//A utility function for parsing out start and end dates
function parseDates() {
var dates = $(this).siblings("label").find("small").html().split("-"),
start = dates[0].split(" "),
end = dates[1].split(" ");
//If no month in end date, assume same month as first (Ex. Jul 06-22 == Jul 06 - Jul 22)
if (end.length == 1) {
end.unshift(start[0]);
}
var obj = {
start: Date.parse(start.join(" ") + ", " + year), //rejoin
end: Date.parse(end.join(" ") + ", " + year) //rejoin
}
// Test for the date range spanning a New Year.
// If necessary, reparse `end` with next year's date
if(obj.end < obj.start) {
obj.end = Date.parse(end.join(" ") + ", " + (year + 1));
}
//return an object with .start and .end properties
return obj;
}
编辑 2
要在页面加载时执行,触发第一个复选框的点击处理程序:
$("#gform_11 input[type=checkbox]").click(function() {
... ...
}).eq(0).triggerHandler('click');
第一个复选框是否被选中并不重要,因为无论元素的 :checked 状态如何,所有内容都会一直计算。