You can chain jQuery methods in a way that makes your code more readable, and allows you to be more expressive in the way that you traverse and manipulate DOM elements
Most of us are introduced to jQuery via the following scenario: when the user clicks an element, you want something to happen to that element. You Google the code, you copy the code, you edit the code so that it matches your DOM elements, it works, you are hooked, you add “jQuery” to your resume. An oft-told tale.
But, what about when the user clicks an element, and we want numerous thing to happen to elements that are in the neighborhood? Perhaps we want the parent element to turn blue, and then we want the <a> inside of the <span> that is a sibling to change it’s href attribute….etc. Sure, we can do all this using jQuery methods such as parent(), find() and end(). But the code starts to get a little verbose. One way in which we can write this kind of code in a slightly more elegant manner is by chaining method calls together. It makes the code more expressive and a little easier to read.
Example # 1
1 2 3 4 5 6 7 |
$(document).ready(function(){ $("div#foo div.inside p a.extra").click(function(){ $(this).css("background-color","yellow"); var parent = $(this).parent(); $(parent).css("background-color","red"); }); }); |
In example # 1, we query a specific selector, change its background color, use the parent() method to find the element’s parent, and then change the parent element’s background color to red. Pretty simple stuff. But, this code can be written better.
Example # 2 A
1 2 3 |
$("div#foo div.inside p a.extra").click(function(){ $(this).css("background-color","yellow").parent().css("background-color","red") }); |
Example # 2 B
1 2 3 4 5 6 |
$("div#foo div.inside p a.extra").click(function(){ $(this)// the element that was clicked.... .css("background-color","yellow") // change the background color of the clicked link to yellow .parent() // select the parent element: '<span>' .css("background-color","red") // change the background color to red }); |
In example # 2 A, because $(this) returns a jQuery object, we can avoid further queries by simply “chaining” subsequent method calls. Chaining refers to using the return value of one method to kick off another method call, and so on. The concept is like that of a “chain reaction” in that one return value drives the call to the next method, and so on. In example # 2 B, we have the exact same code, but we break each of the “chained” methods calls to a new line, which makes the code even more expressive and easier to follow (comments have been added as well). JavaScript does not care about this white space, so you are free to organize your code in any way you like, which allows you to “express” your thoughts, or “logic” in a way that you feel works best.
This next example is a bit long, but what I wanted to accomplish was:
- Provide full page markup so that you can copy the entire code, paste it into notepad and run the file, or use jsfiddle.net
- Create an example where we chain methods together that walk up and then down the DOM, mutating multiple elements, without ever having to create another query
Example # 3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>jQuery - Method Chaning - Example</title> <script src="http://code.jquery.com/jquery-1.6.4.min.js"></script> </head> <script> $(document).ready(function(){ $("div#foo div.inside p a.extra").click(function(){ $(this) .css("background-color","yellow") .parent() .css("background-color","red") .parent() .css({ "font-family": "georgia", "font-size": "22px", "color": "green" }) .find("span.inside") .css("text-decoration","underline") .find("a") .attr({ "href" : "http://www.apple.com", "target" : "_blank" }) .text("now I am a link to apple.com") .end() .end() .end() .end() .append(" -> more text added to a.extra "); }); }); </script> <body> <div id="foo"> <div class="inside"> <p>Item A <span class="inside">inside content <a href="#">inside link</a> </span> <span class="extra">extra content here... <a href="#" class="extra">extra link</a> </span> </p> <p>Item B <span class="inside">inside content <a href="#">inside link</a> </span> <span class="extra">extra content here... <a href="#" class="extra">extra link</a> </span> </p> <p>Item C <span class="inside">inside content <a href="#">inside link</a> </span> <span class="extra">extra content here... <a href="#" class="extra">extra link</a> </span> </p> </div> </div> </body> </html> |
In example # 3, we use the jQuery parent(), find(), and end() methods to move up and then back down the DOM, mutating elements along the way, without ever having to write a second query. The next example is the exact same code, but heavily commented, to make it easier to follow-along.
Example # 4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>jQuery - Method Chaning - Example</title> <script src="http://code.jquery.com/jquery-1.6.4.min.js"></script> </head> <script> $(document).ready(function(){ $("div#foo div.inside p a.extra").click(function(){ $(this) // change the background color of the clicked link to yellow .css("background-color","yellow") // select the parent element: '<span>' .parent() // change the background color to red .css("background-color","red") // select the parent element: <p> .parent() // change three css properties in one statement by passing an an object as an argument to the .css() method .css({ "font-family": "georgia", "font-size": "22px", "color": "green" }) // find and select the span inside of this <p> tag that has the class "inside" .find("span.inside") // add an underline .css("text-decoration","underline") // find and select the <a> tag inside of this element .find("a") // change the href and target elements .attr({ "href" : "http://www.apple.com", "target" : "_blank" }) // change the element's text property .text("now I am a link to apple.com") // return to selection: <span.inside> .end() // return to selection: <p> .end() // return to selection: <span > .end() // return to original selection: "div#foo div.inside p a.extra" .end() // append some text .append(" -> more text added to a.extra "); }); }); </script> <body> <div id="foo"> <div class="inside"> <p>Item A <span class="inside">inside content <a href="#">inside link</a> </span> <span class="extra">extra content here... <a href="#" class="extra">extra link</a> </span> </p> <p>Item B <span class="inside">inside content <a href="#">inside link</a> </span> <span class="extra">extra content here... <a href="#" class="extra">extra link</a> </span> </p> <p>Item C <span class="inside">inside content <a href="#">inside link</a> </span> <span class="extra">extra content here... <a href="#" class="extra">extra link</a> </span> </p> </div> </div> </body> </html> |
In example # 4, we have the exact same code as example # 3, with comments added.
Summary
When a jQuery method returns a jQuery object, you can take advantage of that behavior by “chaning” subsequent method calls to the return value of the previous method. When using this approach, you can execute multiple DOM statements from the result of one query. The end result is code that is more expressive and easier to read.
Helpful links for chaining jQuery methods
http://ejohn.org/blog/ultra-chaining-with-jquery/
http://paulirish.com/2008/sequentially-chain-your-callbacks-in-jquery-two-ways/
http://forum.jquery.com/topic/jquery-method-chaining-returned-object-something-i-don-t-get
http://www.jquery-tutorial.net/introduction/method-chaining/