Search code examples
jqueryparenttraversalclosestparents

jQuery closest(), parents() and parent() affects multiple elements at same DOM level


I am trying to traverse up the DOM to the closest DIV. The markup below is below.

<div>
     <span>
           <a class="anchor">Text</a>
     </span>
</div>
<div>
     <span>
           <a class="anchor">Text</a>
     </span>
</div>
<div>
     <span>
           <a class="anchor">Text</a>
     </span>
</div>

When I use any of the following:

$('.anchor').closest('div').css('background-color', 'red');
$('.anchor').parents('div').css('background-color', 'red');
$('.anchor').parent().parent().css('background-color', 'red');

It affects all the DIVs like so:

<div style="background-color: red">
     <span>
           <a class="anchor">Text</a>
     </span>
</div>
<div style="background-color: red">
     <span>
           <a class="anchor">Text</a>
     </span>
</div>
<div style="background-color: red">
     <span>
           <a class="anchor">Text</a>
     </span>
</div>

If I were to click the middle anchor I want this:

<div>
     <span>
           <a class="anchor">Text</a>
     </span>
</div>
<div style="background-color: red">
     <span>
           <a class="anchor">Text</a>
     </span>
</div>
<div>
     <span>
           <a class="anchor">Text</a>
     </span>
</div>

I think I see why closest() would match all three DIVs as the closest DIV to the clicked anchor as it is generically matching DIV.

But when using parents() or parent() it's not as clear as the other DIVs are not a parent of a click anchor. But I can also see where it might just be generically matching DIVs again at that level in the DOM. Although it seems like parents() and parent() should maintain more of a contextual context when matching.


Solution

  • When you specify $(".anchor"), it is finding all the objects in your page that match the .anchor selector and then, one by one, doing .closest('div').css('background-color', 'red') on each of them. If you want to scope it to only the parent div of the object that was clicked on, you need to use the click-on object as the starting point for your .closest('div') call like this:

    $(this).closest('div').css('background-color', 'red');
    

    This will then only affect the clicked on parent div starting from the this object.

    You haven't shown the code for you click handler, but it could be like this:

    $(".anchor").click(function() {
        $(this).closest('div').css('background-color', 'red');
    });
    

    or, if you wanted to clear the other items that might have been red from previous clicks and then make this one red, you could do this:

    $(".anchor").click(function() {
        var master$ = $(this).closest('div')
        master$.siblings().css('background-color', 'white');
        master$.css('background-color', 'red');
    });