Where Marketing, Analytics, and UX meet

JavaScript: Top jQuery tips

JavaScript client-side tutorial series image

JavaScript is incredibly powerful but it doesn't follow the rules of a lot of different languages. One of the best companion frameworks to JavaScript would be jQuery. It makes it possible to quickly manage interactive events, select elements in the HTML interface, and efficiently write reusable functionality to manipulate the HTML document object model. This post will introduce a number of tips that every js coder should know.

This post is a part of a series! Check out the JavaScript Client-Side Tutorial Series! 

Learning JavaScript is like mastering any tag-soup language, filled with lots of functionality but not organized in namespaces that help the learner embrace more advanced capabilities. In addition to that, there are also a number of browser implementation differences for JavaScript that still mean we have to fork versions of our code in order to handle more complex goals in a manner that still work in a majority of the most popular Web browsers. jQuery solves that reality by wrapping some of the most common code-forking realities into a common set of jQuery functions that play nice in most browsers.

Before we get started, I want to say that it is important that developers understand what jQuery is accomplishing for them. I am not writing this post for the script kiddies that want to find "cut-n-paste" shortcuts to their endgame. If you have stumbled across this post and are not familiar with the basics of jQuery, then go read the earlier posts in this series. Then come back and learn some of the tricks I present here.

One more disclaimer: I know there are plenty of people out there who are javascript purists. I know that feeling. You want your code to be light and fast. But here is the thing. I am confident that, theoretically, I can write fewer Kbytes of code than would be required to load the jQuery framework, in extremely special situations. But in reality, consider that jQuery compressed weighs in at 32 Kbytes and when it comes to CSS DOM selection in the Chrome browser, native JavaScript can run about 3 million selections per second whereas jQuery can only run a little over 2 million. So, unless you are talking about writing millions of operations  in less than 32 Kbytes of JavaScript code, I think it is safe to take advantage of the benefits of jQuery versus reinventing the wheel. But you should still take responsibility for understanding the wheel!

Here are the top most frequent issues I hear new jQuery developers trying to master:

  • Why can't I refer to jQuery by the alias "$"?
  • I know the element is there, but why can't jQuery find the element I am targeting?
  • How do I safely select an element with no CSS classes on it?
  • How do I find an element inside my currently selected element?
  • How do I add a single click event to a bunch of buttons and know which button I clicked in the event?

Let's go through each of these, one at a time.

Why can't I refer to jQuery by the alias "$"?

The jQuery framework is really popular. But there are all sorts of other JavaScript frameworks that are extremely popular and used by a number of plugins, all competing to use the "$" alias. In this common question, I watch someone trying to write code like...

$('button.submit').addClass('disabled');

 and they are getting back an error like "$ is not defined" by the browser. As a result, they quickly figure out they can write the following as an alternative:

jQuery('button.submit').addClass('disabled');

By default, jQuery loads a variable named "jQuery" as a global object in your page. And a number of languages and plugins often try to assign the "$" symbol as an alias to their default global object name. In that case, you might even have the alias "$" defined, but it acting as the alias to the global "jQuery" object. So here is the best practice for being sure you code can use the "$" alias within the context of the code you are writing: Put your personal code inside a self-executing anonymous function and closure, and pass jQuery into the anonymous function while assigning it the alias "$". Let's see how that works:

//this is the start of the closure, and where creates the "$" alias
  (function( $ ){

      // This is where your code should now go.
      $('button.submit').addClass('disabled');


// this is the end of the closure and where we inject jQuery
   })( jQuery );

Closures as functions can be executed immediately after defined, just as we are doing here. We are passing a single parameter to the closure/anonymous function, specifically passing jQuery into the closure. Within the definition of the anonymous function inside the closure we name that single parameter "$". Since we know we have passed jQuery in, and inside the function that parameter is named "$", we can now refer to jQuery by simply typing the $ symbol. 

I know the element is there, but why can't jQuery find the element I am targeting?

Let's imagine you have a page that looks like the following:

<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-2.1.4.js"></script>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
  <div class="myClass">Hello world</div>
  <script>
    (function($){

      alert(  $('div.myClass').html()  );
    
     })(jQuery);
  </script>
</body>
</html>

Now, you would expect the page to load and an alert to pop-up saying "Hello world", since the jQuery is supposed to select the above DIV with the CSS Class named myClass, but for some reason it cannot find the DIV, let alone the containing HTML text within the DIV.

This is the first lesson nearly everyone learns when using jQuery. The above example isn't very realistic. More than often it will popup the alert perfectly well. But if we had a much larger page, it might not. That is simply because jQuery and your script might load and run before all of the HTML of the page has completed loading. Technically, since jQuery is really fast, it might search for stuff in the HTML that hasn't shown up yet!

To avoid this, you need to run your jQuery code within a document-level event called "ready". The document ready event fires in the browser when all of the document object model (DOM) of the HTML has loaded into memory, but the browser has not displayed it yet. Let's look at how the code would change.

 

<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-2.1.4.js"></script>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
  <div class="myClass">Hello world</div>
  <script>
    (function($){

      $( document ).ready(function(){

          alert(  $('div.myClass').html()  );

      });

     })(jQuery);
  </script>
</body>
</html>

Simply wrapping your code inside the document ready code ensures that all of the scripts and HTML has loaded into memory, but it not yet displayed. Your code would then run, doing whatever you want to do to add new HTML, connect events to the interface, or hide items, and THEN the browser will show the content of the page to the user.

Remember, jQuery can run about 2 million instructions before the browser shows the page to the user. So you shouldn't have to worry about slowing down the page load too much with this best practice.

How do I safely select an element with no CSS classes on it?

This is a tricky question because there is no silver bullet to solve this issue. Let's look at some HTML and talk about why is it complicated and learn a trick that might help in a number of situations.

<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-2.1.4.js"></script>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
  <div>
    <!-- first group: start
         we don't care about this -->
    <div>
      <div>I'm first</div>
      <div>I'm the second sibling</div>
      <div class="anotherDiv">I'm the third sibling</div>
    </div>
    <!-- first group: end -->
  </div>
  <div>
    <!-- second group: start
         We want to grab the div with no class below this
         containing the three sibling divs-->
    <div>
      <div>I'm first</div>
      <div>I'm the second sibling</div>
      <div class="anotherDiv">I'm the third sibling</div>
    </div>
    <!-- second group: end -->
  </div>
  <script>
    (function($){
      //how do we grab the second group of sibling divs?
    })(jQuery);
  </script>
</body>
</html>

Now, if you wrote the above HTML and wanted to grab the DIV that wraps the second set of siblings, then you could just give the DIV an id or unique class name and be done with it. But let's imagine you didn't write the HTML markup, you can't change it, and you still need to write some JavaScript to select that DIV with no ID or unique CSS Class.

We are going to use two techniques in jQuery to pull this particular example off. First note, this technique only works if the HTML is consistently presented like this. If the markup is consistent, let's have a look at how to grab a group of selections based on specifying a non-unique CSS Class, and then traverse the parents to grab the DIV with no unique selector attributes. Here is the solution:

<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-2.1.4.js"></script>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
  <div>
    <!-- first group: start
         we don't care about this -->
    <div>This is the first group 
      <div>I'm first</div>
      <div>I'm the second sibling</div>
      <div class="anotherDiv">I'm the third sibling</div>
    </div>
    <!-- first group: end -->
  </div>
  <div>
    <!-- second group: start
         We want to grab the div with no class below this
         containing the three sibling divs-->
    <div>This is the second group 
      <div>I'm first</div>
      <div>I'm the second sibling</div>
      <div class="anotherDiv">I'm the third sibling</div>
    </div>
    <!-- second group: end -->
  </div>
  <script>
    (function($){
      $( document ).ready(function(){

        var targetChild = $('.anotherDiv')[1];
        var targetParent = $( targetChild ).parent();
        console.log( $( targetParent ).html() );
      
        //shorter syntax
        console.log( $( $('.anotherDiv')[1] ).parent().html() );
      
       });
    })(jQuery);
  </script>
</body>
</html>

In our solution here, what we do is target the CSS Class anotherDiv which returns two found object. Like most things in JavaScript, the array of two found objects is zero-based, meaning the first of the two divs with the anotherDiv CSS Class would be item #0, and the second div would be item #1. So the first line of code in our ready event selects the elements with the anotherDiv Class attached, and then we immediately return the second item of the two.

This gets us a DIV within the DIV we really want to target in the second group. In the next line of code, we go after the parent. To do this we need to wrap the targetChild variable with the jQuery selector function.

$( targetChild )

Doing this takes the targeted child element from the first line, and reselects it wrapped in jQuery and all of the jQuery functionality. From there we can request the parent of that object and return it to a variable.

var targetParent = $( targetChild ).parent();

At this point, the variable targetParent should be pointing at the div that has no unique selectors. To grab the contents of that element, we simply wrap it in jQuery again and request the HTML associated with the targetParent element:

$( targetParent ).html()

Sending that to the JavaScript console in the browser would return the following:

"This is the second group 
      <div>I'm first</div>
      <div>I'm the second sibling</div>
      <div class="anotherDiv">I'm the third sibling</div>
    "

That is what we wanted to select!

How do I find an element inside my currently selected element?

We did something similar to this in the previous example, but in this example, we are going to make use of the jQuery find method. Let's look at some HTML.

<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-2.1.4.js"></script>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
  <div class="favorite-foods">
    <ul>
      <li>Pizza</li>
      <li>Sushi</li>
      <li>Ezekeal Bread</li>
    </ul>
  </div>
  <div class="favorite-books">
    <ul>
      <li>Jungle Book</li>
      <li>Moby Dick</li>
      <li>The Lion, The Witch, and the wardrobe</li>
    </ul>
  </div>
  <script>
    (function($){
      $( document ).ready(function(){

        var books = $( '.favorite-books' );
      //How do we select our favorite book "Moby Dick" 
      //from the books variable.

      });
    })(jQuery);
  </script>
</body>
</html>

Like in the previous example, we are going to need to wrap the books variable object in jQuery so we can evoke the find method, to which we can make a sub-selection. Let's view an update to the script.

  <script>
    (function($){
      $( document ).ready(function(){
        
        var books = $( '.favorite-books' );
        console.log( $( books ).find('li:nth-child(2)').html() );
        
        //shorter version
        console.log( $( '.favorite-books' ).find('li:nth-child(2)').html() );
        
      });
    })(jQuery);
  </script>

jQuery's find method lets us perform a sub-selection within something else we have already selected. Pretty straight forward.

How do I add a single click event to a bunch of buttons and know which button I clicked in the event?

This little tutorial will bring together all of the tutorials you have learned in the above page. If anything seems confusing, refer to the above tutorials for more understanding.

You might have a bunch of buttons on an interface that needs to do a similar action to a set of sibling elements. In a simple example, we might have a list of names in a table. When we click a button at the end of a table row with a name, we want that button to pop up a greeting using the name in the row. To do this, we could write a function for each button, but the functionality is identical, so that feels like a waste of resources. But if we write a single function and attach it to the click event of all of the buttons, then we need a way to know which button we clicked so we can figure out which name to greet based on the row it is in.

Let's take a look at this example:

<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-2.1.4.js"></script>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
  <table>
    <caption>Welcome everyone</caption>
    <thead>
      <tr>
        <th>Name</th><th>Greeting</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td class="name">Cruz</td><td><button class="greeting" id="button-1">Say hello</button></td>
      </tr>
      <tr>
        <td class="name">Rubio</td><td><button class="greeting" id="button-2">Say hello</button></td>
      </tr>
      <tr>
        <td class="name">Kasich</td><td><button class="greeting" id="button-3">Say hello</button></td>
      </tr>
      <tr>
        <td class="name">Trump</td><td><button class="greeting" id="button-4">Say hello</button></td>
      </tr>
    </tbody>
  </table>
  <script>
    (function($){
      $( document ).ready(function(){
        
        //How do we write a single click event
        //for all of the buttons, that will know
        // which name to greet in the row containing
        // the button clicked?
        
      });
    })(jQuery);
  </script>
</body>
</html>

Let's first update the script and figure out how to assign a click event to each of the buttons.

 <script>
    (function($){
      $( document ).ready(function(){
        
        $( '.greeting' ).on('click', function(){
          alert( 'You clicked me' );
        });
        
      });
    })(jQuery);
  </script>

Simply selecting the CSS Class greeting associated with all of the buttons selects all of the buttons. jQuery contains what is called "chainable" methods. This means that each method call returns a jQuery Object, and you can perform another function on that resulting jQuery Object immediately. So with the resulting list of buttons, we next call the jQuery "on" method. This lets us assign one of the on events to all of the button elements. We want to assign the "click" event, so you can see here we are referencing the "click" event immediately. The second parameter of the on method expects to receive a function. jQuery associated this function code with the click event for all of the button elements. Now, when someone clicks one of the buttons, it should show a popup message stating "You clicked me".

Let's update the script and see if we can alert the id of the button we are specifically clicking.

  <script>
    (function($){
      $( document ).ready(function(){
        
        $( '.greeting' ).on('click', function(){
          alert ( "you clicked " + $( this ).attr('id') );
        });
        
      })
    })(jQuery);
  </script>

Within the on method's click function we are now using the this keyword. Within the click event, this refers to the button we have specifically clicked. By wrapping the this Object with jQuery we can now use the attr method, which returns the value of attributes associated with a selected element. Because our selected element is this, and this is our clicked button, the attribute id should return the id of the button we have clicked. We now know how to figure out which button we are clicking. Recall that all of the buttons are sharing the same function right now. But we are able, within the click function and using the this keyword, to figure out which button we are clicking.

Let's wrap this up by using the other above lessons to figure out how we can say hello using the name specified within the row of the button we have clicked. Check out the updated function.

  <script>
    (function($){
      $( document ).ready(function(){
        
        $( '.greeting' ).on('click', function(){
          alert( "Hello " + $( this ).parent().parent().find('.name').html() );
          //alternative below
          alert( "Hello " + $( this ).parents('tr').find('.name').html() );
        });
        
      })
    })(jQuery);
  </script>

The above shows two ways to pull this off. The first way might have been how you would have figured it out based on the above tutorials on the page. In the first line within the click function, we wrapper this with jQuery and use the parent method, which would be the TD tag. From that TD tag, we request it's parent, which should be the TR tag for the whole row relative to the clicked button. From there we can use the find method to search for the child TD tag within the row. And once it finds that, we can request the HTML within that TD element, which would return the name in the row next to our clicked button. That seems fairly straight forward and understanding that jQuery is chainable would have hinted that we could directly use the parent method twice to get the parent element of the parent element and return the TR element.

The alternative would be to use jQuery's parents method. The parent method we learned above only attempts to return the exact parent to the selected element. In contrast, the parents method returns the entire hierarchy of parents above the selected element as an array of elements. In the case of the this keyword, we have a button. The parents method would have identified an array of parents for the clicked button, which would have been [ TD, TR, TBODY, TABLE, BODY ] if you review the above markup.

The parents method also accepts a single optional parameter: some selector syntax. So by passing in "TR" to the parents method in the above script, we are asking for one of the parents that match the selector "TR" which would have returned the single TR element from the array of parents. From there we can use the find method on that parent to search for the element with the CSS Class "name" and return the HTML of that matching element, which should be the name in the button's row. That should do it!

If I think of more examples with which people often struggle, I will append it here. In the meantime, I hope this was helpful. Leave me a message here or on twitter if you have any feedback.

 

Add new comment

*

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.
By submitting this form, you accept the Mollom privacy policy.