Skip to content Skip to tags Skip to twitter news Skip to blog roll Skip to categories Skip to archives Skip to recent posts

November 16, 2008

2 Comments

Better jQuery Code #2

by in jQuery,Tips,Web Development on November 16, 2008 @ 12:00 pm

In a follow up to my Better jQuery Code #1 post I will be writing about some other small items that I have found to make my code better and more readable.

Chaining

Chaining is one of the most beautiful and time save pieces of code structure that jQuery brought to the game, the problem is is that it can make the code unreadable if not treated correctly.

For example, say you wanted to select the fourth LI in your nav and add a class, remove a class from it, then you want to find the UL that is a child of that LI and add a class to that, then want to move back to the UL that has the ID nav on it (.end() goes back to the last ‘destructive’ operation) and lastly you want to animate that UL. Along with have a heft run on sentence you also have a pretty unreadable string of functions.

  1. $('#nav').find(> li').eq(3).addClass('className').removeClass('otherClass').find('ul').addClass('redClass').end().end().end().slideUp().slideDown();

Instead, format you code to look something like below, you can have more then one methods per line, but keep it reasonable and readable. See how I am indenting each line? This is to give it a sense that each method is referring to specific elements. Much like you would indent your HTML and how some people indent their related CSS, it is good practice to indent your code.

  1. $('#nav')
  2.     .find('> li')
  3.         .eq(3)
  4.         .addClass('className')
  5.         .removeClass('otherClass')
  6.         .find('ul')
  7.             .addClass('redClass')
  8.         .end()
  9.     .end()
  10. .end()
  11. .slideUp()
  12. .slideDown();

A small caveat to the above structure is that if you run your code through JavaScript Lint you will get a notice of “lint warning: unexpected end of line; it is ambiguous whether these lines are part of the same statement,” I personally don’t see an issue with this and will just to a find and replace for the line break and all is good.

Traversing (Finding)


Last post I posted about eq, hasClass, is, and not
which are four traversing methods for filtering out certain items from your select. For returning specific elements from the DOM using the children(), siblings(), parent(), and parents() methods in most of my projects.

The Core developers for jQuery are very smart people

The Core developers for jQuery are very smart people, they name methods the make a lot of sense and match up to the functionality they provide and children() is not an exception. Let’s assume we have the following DOM structure:

  1. <ul id="nav">
  2.     <li><a>Text</a></li>
  3.     <li><a>Text</a></li>
  4.     <li><a>Text</a></li>
  5.     <li><a>Text</a></li>
  6.     <li> <a>Text</a>
  7. <ul>
  8.     <li><a>text</a></li>
  9. </ul>
  10. </li>
  11.     <li><a>Text</a></li>
  12.     <li><a>Text</a></li>
  13. </ul>

With that structure, we did:

  1. $('#nav').children();

How many elements would be returned? 17? 15? 7?

If you said 7 then you are correct; why not 17 or 15? Imagine this, you have a single parent, and you have 6 brothers each of whom have a significant other. You and your significant other have a daughter and she in turns has a kid but is single and that kid has a childhood sweetheart. In this scenario “#nav” is your mother (we’ll cover the parent and parents method below but keep this in your head) and when we say give me all your children we are only look for your mothers immediate children, which in this case are the LI.

Got that?

Ok, now what do you get if you do the following with the siblings() method?

  1. $('li:eq(4)').siblings()

If you said 6, you are correct, siblings will select all your immediate brothers and sisters. You following me so far? Does this make sense? In this example we are saying select the LI that is in the forth index (or in this case, you) and then get my brothers and sisters or siblings.

Just for a teaser, what if you wanted to something to you and your siblings? Easy, just add .andSelf() at the end (this would probably be used in a case where you click on a LI and do $(this)). We’ll cover this a bit more in a later post.

  1. $('li:eq(4)').siblings().andSelf()

The .parent() method is pretty straight forward, it will select your immediate parent. So in the following case you will select the UL.

  1. $('li:eq(4)').parent()

The parent() method excepts an expression but the only need I’ve ever had was to quickly test the parent for something particular, maybe a class or a specific attribute or attribute with a certain value, in an IF statement. (remember, in JavaScript 0 is treated at false and 1 is treated as true)

  1. if( $('li:eq(4)').parent('.selected') ){
  2. if( $('li:eq(4)').parent('[data]') ){
  3. if( $('li:eq(4)').parent('[start=5]') ){

The parents() method can be a little more powerful for your needs, but is useful in some cases. Let’s assume that the UL above is the only code in your body tag. So if you do the following how many items will be returned? 1? 2? 3? 4?

  1. $('li:eq(4)').parents()

If you said anything but 3 you would be incorrect, if the UL code above was the only child of the body tag that the JavaScript code above would return the UL, BODY, and HTML tags. With the parents method you can filter it down to what you want by using any number of selectors that jQuery supports.

Below is a piece of code from a project I’ve been working on. Basically the issue was that there needed to be a submit button appended after the last input box on the page. If that input box is inside of table, append the button after the table. The issue was, I had not idea what the TABLE may be in, could have been a DIV that is inside of a DIV and so on. Also keep in mind that as of this writing I see at least one better way to have written out this code but for this post this example should work fine.

  1. // inlineTextQuestion is a reference to all the input elements
  2. var lastOne = inlineTextQuestion.eq( inlineTextQuestion.size()-1 );
  3. var lastOneParents = lastOne.parents();
  4. var lastOneParent = null;
  5.  
  6. lastOneParents
  7. .each(function(i){
  8.     if( lastOneParent === null ){
  9.         var el = $(this);
  10.         // #bodyText is the one known factor I had
  11.         if( el.parent().is('#bodyText') ){
  12.             lastOneParent = el;
  13.         }
  14.     }
  15. });
  16.  
  17. // sbmt is a reference to a submit button create about this code
  18. lastOneParent.after(sbmt);

Let me try to explain what is going on, please refer to the comments in the code for what the variables are reference to, line 2 I am grabbing a reference to the last INPUT in the inlineTextQuestion variable. Line 3 I grabbed a reference to the all the parents of that INPUT. Line 6/7 I loop through all the parents checking , at line 11, to see if the current element’s parent is the DIV with the ID of “bodyText.” If that returns true we set a reference to that element and at line 18 I append the submit button after that referenced element.

Closing

In this post we discussed using the children(), siblings(), parent(), and parents() methods and I try to explain them the way I see them. These are the ones I use the most and the ones I think you will find the love for.

If there is anything with the above you don’t under stand or, god forbid, I got incorrect, please feel free to drop me a line.

back to beginning of this post back to skip to links
Tags:

If you liked this article why don't you share it:

Stumble it delicious Digg it Reddit it DZone it Bump it Mixx it! Buzz up! E-mail

2 Responses to “Better jQuery Code #2”

Thanks again. As I said in your last post, I’m learning jQuery. I was not so sure about how to use “.end()”, but your chaining example made it clear.

Trackbacks

  1. JeremiahTolbert.com » Blog Archive » links for 2008-11-19

Learn from my mistakes, I got burnt by the flame, you don't have to.


RSS Feed Link My Hosting of Choice

67 queries. 0.340 seconds. Powered by WordPress visitor stats