The closest selector affects more than one element
I have an asp.net application that uses a grid control with three columns of checkboxes side by side. The boxes in the first column are included; the next two are disabled. I tried to write a JQuery function that will include an adjacent checkbox in the second column when the user checks the field in the first column. Here is my code:
<script type="text/javascript">
$(document).ready(function() {
$("[id$='FirstCheckBox']").click(function() {
var td = $("td", $(this).closest("tr"));
if ($(this).is(":checked")) {
$("input[type=checkbox]", td).prop("disabled", false);
}
else {
$("input[type=checkbox]", td).prop("disabled", true).prop("checked", false);
$(this).prop("disabled", false);
}
});
});
</script>
This function works great when I only have two checkbox columns. But when I add a third column with the checkboxes disabled, the function also includes a field in that column. I thought the closest selector only selects one element, but it seems to select two. What am I doing wrong?
source to share
Instead of navigating to the parent element entirely tr
, just navigate to the closest one td
and find the next cell using the jQuery method next()
.
You can generalize this by changing your code to this:
<script type="text/javascript">
$(document).ready(function() {
$("#tableId").on('click', 'input:checkbox:not(:disabled)', function() {
var $nextTd = $(this).closest("td").next('td');
if (! $nextTd.length) { return; } // already in last column
if ($(this).is(":checked")) {
$("input[type=checkbox]", $nextTd).removeProp("disabled");
}
else {
$("input[type=checkbox]", $nextTd)
.prop("disabled", 'disabled')
.removeProp("checked");
$(this).removeProp("disabled");
}
});
});
</script>
source to share
What if you set checkboxes to an array of item objects and use an index within the array to set which checkbox you want to enable / disable. I thought something like this: DEMO
var chx = $('input[type="checkbox"]'); // Store the elements
chx.change(function(){ // Set the event listener
var i = chx.index(this); // Get the index of the clicked element
$(chx[i + 1]).prop('disabled', function(i, val){
return !val; // Return the opposite state of the element indexed after the triggered element
});
});
It has the advantage of being short and sweet, and allows you to manipulate the index rather than conditionals. I suppose you could add a legend if you want more control.
Here is an example of using a condition to restrict the functionality of certain elements in an array. This restricts events from any elements in the array after the first.
var chx = $('input[type="checkbox"]');
chx.change(function(){
var i = chx.index(this);
if(i == 0){
$(chx[i + 1]).prop('disabled', function(i, val){
return !val;
});
}
});
This is an even shorter version as you need it to be applied to the first checkbox, but it still allows you to skip DOM traversal.
var chx = $('input[type="checkbox"]');
$(chx[0]).change(function(){
$(chx[1]).prop('disabled', function(i, val){
return !val;
});
});
I also updated the script to reflect this change.
Hope this helps! Let me know if you have any questions.
source to share