Thursday, July 3, 2014

jQuery: Closest Is Better Than Parent

We know that jQuery is the de-facto DOM traversal tool on the web. Part of what makes this works so well with jQuery is it's chaining ability. You can chain just about everything you need to do as a single statement, without sacrificing readability. There are some scenarios where chaining these traversal operations doesn't work so well. Like when trying to traverse up through the DOM using parent().

Let's say you had a DOM structure that looks something like this.

<div data-foo="bar">
    <p>Please <a href="#">click</a></p>
</div>

When the link is clicked, we need access to the foo data attribute. So the naive solution might be to do something like this.

$( 'a' ).on( 'click', function( e ) {
    var foo = $( e.currentTarget )
        .parent()
        .parent()
        .data( 'foo' );
});

The problem with chaining parent() calls together, is that it's a fixed structure inside of our callback handler. Not only is it verbose code, it's also vulnerable changes in the DOM. Let's say that we've decided to remove the p element from our markup.

<div data-foo="bar">
    Please <a href="#">click</a>
</div>

All of the sudden, our approach that chained together the parent() calls no longer works. The better approach is to use closest().

$( 'a' ).on( 'click', function( e ) {
    var foo = $( e.currentTarget )
        .closest( 'div' )
        .data( 'foo' );
});

The not only is the closest() approach immune to changes, within reason, to the DOM structure, but it's also efficient and easy to read. As soon as it finds an element, it stops looking, which is ideally suited to the majority of use cases like this.