{"id":1057,"date":"2012-05-10T00:20:19","date_gmt":"2012-05-09T22:20:19","guid":{"rendered":"http:\/\/doanduyhai.wordpress.com\/?p=1057"},"modified":"2012-05-10T00:20:19","modified_gmt":"2012-05-09T22:20:19","slug":"jquery-chaining","status":"publish","type":"post","link":"https:\/\/www.doanduyhai.com\/blog\/?p=1057","title":{"rendered":"jQuery wrapped-set chaining"},"content":{"rendered":"<p>In this article we explore the JQuery chaining internal mechanism to see how it works and how it can  improve our web development.<\/p>\n<p><!--more--><\/p>\n<h1>I The &#8220;wrapped set&#8221;<\/h1>\n<h3>A)  Definition<\/h3>\n<p> If you are a regular user of JQuery, you have probably heard about the &#8220;<strong>wrapped set<\/strong>&#8221; .In the official documentation the wrapped set is mentionned as simply a jQuery object. <\/p>\n<p>The wrapped set is simply <strong>a list of DOM elements(with their children) in the order in which they are defined in the current document that matches a selector<\/strong>  or  <strong>in the order in which they have been created on the fly with the <em>$(html)<\/em> function<\/strong>.  <\/p>\n<p> Consequently, by definition, a wrapped set is a result of:<\/p>\n<ul>\n<li>either a jQuery selector: <strong>$(&#8216;.elementToBeSelected&#8217;)<\/strong><\/li>\n<li>or a DOM element created on the fly with jQuery: <strong>$(&#8216;&lt;div&gt;&lt;span&gt;Test&lt;\/span&gt;&lt;\/div&gt;&#8217;)<\/strong>. In this case the wrapped set only contains this single element and its children (if any)<\/li>\n<\/ul>\n<p> To be exact, the wrapped set is a <strong>wrapper jQuery object<\/strong> and does not only contains those elements. It also offers numerous handy <strong>jQuery functions<\/strong>. Below is an example:<\/p>\n<pre class=\"brush: xml; title: ; wrap-lines: false; notranslate\" title=\"\">\n&amp;lt;table border=&amp;quot;0&amp;quot; cellspacing=&amp;quot;1&amp;quot;&amp;gt;\n  &amp;lt;thead&amp;gt;\n    &amp;lt;tr&amp;gt;\n      &amp;lt;th&amp;gt;Name&amp;lt;\/th&amp;gt;&amp;lt;th&amp;gt;Sexe&amp;lt;\/th&amp;gt;&amp;lt;th&amp;gt;Age&amp;lt;\/th&amp;gt;\n    &amp;lt;\/tr&amp;gt;\n  &amp;lt;\/thead&amp;gt;\n  &amp;lt;tbody&amp;gt;\n    &amp;lt;tr&amp;gt;\n      &amp;lt;td&amp;gt;John&amp;lt;\/td&amp;gt;&amp;lt;td&amp;gt;Male&amp;lt;\/td&amp;gt;&amp;lt;td&amp;gt;35&amp;lt;\/td&amp;gt;\n    &amp;lt;\/tr&amp;gt;\n    &amp;lt;tr&amp;gt;\n      &amp;lt;td&amp;gt;Sue&amp;lt;\/td&amp;gt;&amp;lt;td&amp;gt;Female&amp;lt;\/td&amp;gt;&amp;lt;td&amp;gt;23&amp;lt;\/td&amp;gt;\n    &amp;lt;\/tr&amp;gt;\n    &amp;lt;tr&amp;gt;\n      &amp;lt;td&amp;gt;Sally&amp;lt;\/td&amp;gt;&amp;lt;td&amp;gt;Female&amp;lt;\/td&amp;gt;&amp;lt;td&amp;gt;28&amp;lt;\/td&amp;gt;\n    &amp;lt;\/tr&amp;gt;\n    &amp;lt;tr&amp;gt;\n      &amp;lt;td&amp;gt;Peter&amp;lt;\/td&amp;gt;&amp;lt;td&amp;gt;Male&amp;lt;\/td&amp;gt;&amp;lt;td&amp;gt;25&amp;lt;\/td&amp;gt;\n    &amp;lt;\/tr&amp;gt;\n  &amp;lt;\/tbody&amp;gt;\n&amp;lt;\/table&amp;gt;\n\n<\/pre>\n<p> The selector <strong>$(&#8216;td:nth-child(1)&#8217;)<\/strong> will give the following wrapped set:<\/p>\n<p> <a href=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/05\/jquery-wrapped-set.png\"><img loading=\"lazy\" src=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/05\/jquery-wrapped-set.png\" alt=\"\" title=\"jquery-wrapped-set\" width=\"358\" height=\"239\" class=\"aligncenter size-full wp-image-1063\" srcset=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/05\/jquery-wrapped-set.png 358w, https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/05\/jquery-wrapped-set-300x200.png 300w\" sizes=\"(max-width: 358px) 100vw, 358px\" \/><\/a><\/p>\n<p> Please notice that the first 4 properties of the <strong>jQuery(&#8216;td:nth-child(1)&#8217;)<\/strong> wrapped set is the 4 <strong>HTMLTableDataCellElement<\/strong> fetched by the selector (from 0 to 3). The following properties are jQuery functions (<em>add<\/em>, <em>addClass<\/em>, <em>after<\/em>&#8230;)<\/p>\n<p>&nbsp;<\/p>\n<h3>B)  jQuery function classes<\/h3>\n<p> Indeed, all jQuery functions can be split into 2 distincts classes:<\/p>\n<ul>\n<li><strong>utility functions<\/strong>: functions that return a scalar value (string, number, void, &#8230;). These functions are of the form: <strong>jQuery.(<em>args<\/em>)<\/strong>  or <strong>$.(<em>args<\/em>)<\/strong>. Example:\n<ul>\n<li><strong>$.trim(<em>value<\/em>)<\/strong>: returns a trimmed string<\/li>\n<li><strong>$.each(<em>container<\/em>,<em>callback<\/em>)<\/strong>: apply the passed called back function to the passed container. Not to be confused with <strong>$(<em>selector<\/em>).each(<em>callback<\/em>)<\/strong><\/li>\n<li><strong>jQuery.parseJSON(<em>jsonString<\/em>)<\/strong>: return a JSON object from an input String representation of the same object<\/li>\n<li>&#8230;<\/li>\n<li>&#8230;<\/li>\n<\/ul>\n<\/li>\n<li><strong>wrapped set functions<\/strong>: functions that act on each element of the wrapped set and return a wrapped set. In this class we distinguish to sub-classes:\n<ul>\n<li><strong>unmodifying wrapped-set functions<\/strong>: functions that do not modify the current wrapped set. The function is applied to each DOM element in the set and the original wrapped set is returned. Example:  <strong>.addClass(<em>cssClass<\/em>)<\/strong>, <strong>.attr(<em>attribute<\/em>[,<em>value<\/em>])<\/strong>, <strong>.each(<em>callback<\/em>)<\/strong>&#8230;<\/li>\n<li><strong>modifying wrapped-set functions<\/strong>: these functions modify the current set to return a subset of its DOM elements. All these functions take a selector as unique argument. Example: <strong>.find(<em>selector<\/em>)<\/strong>, <strong>.closest(<em>selector<\/em>)<\/strong>, <strong>.filter(<em>selector<\/em>)<\/strong>, <strong>.has(<em>selector<\/em>)<\/strong> &#8230;\n\t\t<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>&nbsp;<br \/>\nLet&#8217;s consider the following DOM portion:<\/p>\n<pre class=\"brush: xml; title: ; wrap-lines: false; notranslate\" title=\"\">\n&amp;lt;table border=&amp;quot;0&amp;quot; cellspacing=&amp;quot;1&amp;quot;&amp;gt;\n    &amp;lt;tr&amp;gt;\n      &amp;lt;td class=&amp;quot;centerText&amp;quot;&amp;gt;John&amp;lt;\/td&amp;gt;\n    &amp;lt;\/tr&amp;gt;\n    &amp;lt;tr&amp;gt;\n      &amp;lt;td&amp;gt;Sue&amp;lt;\/td&amp;gt;\n    &amp;lt;\/tr&amp;gt;\n    &amp;lt;tr&amp;gt;\n      &amp;lt;td&amp;gt;Sally&amp;lt;\/td&amp;gt;\n    &amp;lt;\/tr&amp;gt;\n    &amp;lt;tr&amp;gt;\n      &amp;lt;td&amp;gt;Peter&amp;lt;\/td&amp;gt;\n    &amp;lt;\/tr&amp;gt;\n&amp;lt;\/table&amp;gt;\n<\/pre>\n<p><strong>jQuery(&#8216;td&#8217;)<\/strong> will return a wrapped set containing the following DOM elements:<\/p>\n<pre class=\"brush: xml; title: ; wrap-lines: false; notranslate\" title=\"\">\n      &amp;lt;td class=&amp;quot;centerText&amp;quot;&amp;gt;John&amp;lt;\/td&amp;gt;\n      &amp;lt;td&amp;gt;Sue&amp;lt;\/td&amp;gt;\n      &amp;lt;td&amp;gt;Sally&amp;lt;\/td&amp;gt;\n      &amp;lt;td&amp;gt;Peter&amp;lt;\/td&amp;gt;\n<\/pre>\n<p> Now <strong>jQuery(&#8216;td&#8217;).find(&#8216;.centerText&#8217;)<\/strong> will filter the current set with all elements matching the selector. The new wrapped set is:<\/p>\n<pre class=\"brush: xml; title: ; wrap-lines: false; notranslate\" title=\"\">\n      &amp;lt;td class=&amp;quot;centerText&amp;quot;&amp;gt;John&amp;lt;\/td&amp;gt;\n<\/pre>\n<p>&nbsp;<\/p>\n<h1>II Chaining mechanism<\/h1>\n<h3>A)  Internal set stack<\/h3>\n<p> All function chainings in jQuery are based on non-utility functions. You can&#8217;t do chaining with utility functions simply because they only return scalar values and not wrapped set. <strong>Please notice that using an utility function in the middle of a chain will result in stopping it<\/strong> (makes sense).<\/p>\n<p> The idea behing the function chaining is to navigate back and forth between different wrapped sets. Internally jQuery maintains a stack to keep track of all sets it encounters.<\/p>\n<p> Let&#8217;s consider the following DOM section:<\/p>\n<pre class=\"brush: xml; title: ; wrap-lines: false; notranslate\" title=\"\">\n\t&amp;lt;div id=&amp;quot;containterDiv&amp;quot;&amp;gt;\n\t\t&amp;lt;div id=&amp;quot;firstChild&amp;quot;&amp;gt;\n\t\t\t&amp;lt;span class=&amp;quot;centerText&amp;quot;&amp;gt;Test&amp;lt;\/span&amp;gt;\n\t\t&amp;lt;\/div&amp;gt;\n\t\t&amp;lt;div id=&amp;quot;secondChild&amp;quot;&amp;gt;\n\t\t\t&amp;lt;span&amp;gt;Another Text&amp;lt;\/span&amp;gt;\n\t\t&amp;lt;\/div&amp;gt;\n\t&amp;lt;\/div&amp;gt;\n<\/pre>\n<p>  and the following chain <strong>jQuery(&#8216;#containterDiv&#8217;).find(&#8216;div&#8217;).filter(&#8216;#firstChild&#8217;).find(&#8216;span&#8217;);<\/strong><\/p>\n<p> Below is an illustration of how jQuery keeps track of wrapped sets across time:<\/p>\n<p><a href=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/05\/jquery-wrapped-set-navigation1.png\"><img loading=\"lazy\" src=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/05\/jquery-wrapped-set-navigation1.png\" alt=\"jquery-wrapped-set-navigation\" title=\"jquery-wrapped-set-navigation\" width=\"630\" height=\"375\" class=\"aligncenter size-full wp-image-1072\" srcset=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/05\/jquery-wrapped-set-navigation1.png 700w, https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/05\/jquery-wrapped-set-navigation1-300x179.png 300w\" sizes=\"(max-width: 630px) 100vw, 630px\" \/><\/a><br \/>\n&nbsp;<\/p>\n<h3>B)  Inter-sets navigation<\/h3>\n<p> Until now, we only see methods to restrict or filter the current wrapped set. What if we want to come back to the previous set ?<\/p>\n<p> For this, jQuery provides the magical <strong>.end()<\/strong> method. This method simply pop the current wrapped set off the stack and goes back to the previous set.<\/p>\n<p> Now that we understand how the sets are stacked, it&#8217;s easier to navigate through DOM sections using jQuery methods chaining. Let&#8217;s illustrate it by a more complex example:<\/p>\n<p> <strong><br \/>\njQuery (\u2018#containerDiv\u2019)<br \/>\n.find(&#8216;#firstChild&#8217;).attr(&#8216;id&#8217;,&#8221;)<br \/>\n.find(&#8216;span&#8217;).addClass(&#8216;big&#8217;)<br \/>\n.end()<br \/>\n.append(&#8216;<span>After Test<\/span>&#8216;)<br \/>\n.end()<br \/>\n.find(&#8216;#secondChild&#8217;).attr(&#8216;id&#8217;,&#8221;)<br \/>\n.find(&#8216;span&#8217;).addClass(&#8216;bigger&#8217;);<br \/>\n<\/strong><\/p>\n<p><a href=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/05\/jquery-chain-example-part11.png\"><img loading=\"lazy\" src=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/05\/jquery-chain-example-part11.png\" alt=\"jquery-chain-example-part1\" title=\"jquery-chain-example-part1\" width=\"630\" height=\"686\" class=\"aligncenter size-full wp-image-1079\" srcset=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/05\/jquery-chain-example-part11.png 772w, https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/05\/jquery-chain-example-part11-275x300.png 275w\" sizes=\"(max-width: 630px) 100vw, 630px\" \/><\/a><br \/>\n<a href=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/05\/jquery-chain-example-part2.png\"><img loading=\"lazy\" src=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/05\/jquery-chain-example-part2.png\" alt=\"jquery-chain-example-part2\" title=\"jquery-chain-example-part2\" width=\"630\" height=\"533\" class=\"aligncenter size-full wp-image-1077\" srcset=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/05\/jquery-chain-example-part2.png 779w, https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/05\/jquery-chain-example-part2-300x254.png 300w\" sizes=\"(max-width: 630px) 100vw, 630px\" \/><\/a><\/p>\n<p> As you can see, the chaining feature is quite powerfull. You can navigate back and forth in the wrapped-set stack with the <strong>.end()<\/strong> function. <strong>It is even possible to chain multiple .end() successively to navigate many wrapped sets back<\/strong>. It can becomes quickly unreadable so do not abuse of this function too much.<\/p>\n<p>There is a good practice, when using complex chaining, to indent properly your code to make it at least readable and understandable for future developers. The previous chain can be turned into:<\/p>\n<p><strong><br \/>\njQuery(&#8216;#containterDiv&#8217;)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;.find(&#8216;#firstChild&#8217;)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.attr(&#8216;id&#8217;,&#8221;)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.find(&#8216;span&#8217;)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.addClass(&#8216;big&#8217;).end()<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.append(&#8216;<span>After Test<\/span>&#8216;).end()<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;.find(&#8216;#secondChild&#8217;)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.attr(&#8216;id&#8217;,&#8221;)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.find(&#8216;span&#8217;)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.addClass(&#8216;bigger&#8217;);<br \/>\n<\/strong><\/p>\n<p> Each indentation level corresponds to a wrapped set change.<\/p>\n<p>&nbsp;<br \/>\n&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this article we explore the JQuery chaining internal mechanism to see how it works and how it can improve our web development.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[27,13],"tags":[],"_links":{"self":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1057"}],"collection":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1057"}],"version-history":[{"count":0,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1057\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1057"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1057"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1057"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}