Thursday, June 24, 2010

Excellent tips to improve your Jquery programming-Part 2

6/24/2010

In part-1 of this tutorial I told you about basics of jQuery usage. Now I will continue this tutorial with more awesome tips and tricks of jQuery programming. I hope you will love this tutorial like the first one.

Learn to use animate properly

When I first started using jQuery I loved the fact that it was easy to use the pre-defined animations like slideDown() and fadeIn() to get some really cool effects incredibly easy. It's easy to take things further though because jQuery's animate() method is very easy to use and very powerful. In fact, is you look at the jQuery source code you'll see that internally those methods are just shortcuts which use the animate() function.
slideDown: function(speed,callback){  
 return this.animate({height: "show"}, speed, callback);  
},  

fadeIn: function(speed, callback){  
 return this.animate({opacity: "show"}, speed, callback);  
}  

The animate() method simply takes any CSS style and smoothly transitions it from one value to another. So, you can change the width, height, opacity, background-color, top, left, margin, color, font-size, anything you want.
This is how easy it is to animate all your menu items grow to 100 pixels high when you roll over them.
$('#myList li').mouseover(function() {  
 $(this).animate({"height": 100}, "slow");  
}); 

Unlike other jQuery functions, animations are automatically queued, so if you want to run a second animation once the first is finished then just call the animate method twice, no callback necessary.
$('#myBox').mouseover(function() {  
 $(this).animate({ "width": 200 }, "slow");  
    $(this).animate({"height": 200}, "slow");  
});  
If you want the animations to happen concurrently then just put both styles in the params object of a single call, like this...
$('#myBox').mouseover(function() {  
    $(this).animate({ "width": 200, "height": 200 }, "slow");  
});

Learn about event delegation

jQuery makes it easier than ever to attach events to elements in the DOM unobtrusively, which is great, but adding too many events is inefficient. Event delegation allows you to add less events to achieve the same result in many situations. The best way to illustrate this is with an example...
$('#myTable TD').click(function(){  
     $(this).css('background', 'red');  
});
A simple function which turns cells in a table red when you click on them. Let's say that you've got a grid with 10 columns and 50 rows though, that's 500 events bound. Wouldn't it be neater if we could just attach a single event to the table and when the table is clicked have the event handler work out which cell was clicked before turning it red?
Well that's exactly what event delegation is and it's easy to implement...
$('#myTable').click(function(e) {  
    var clicked = $(e.target);  
    clicked.css('background', 'red');  
}); 
'e' contains information about the event, including the target element that actually received the click. All we have to do is inspect it to see which cell was actually clicked. Much neater. Event delegation has another benefit. Normally, When you bind a handler to a collection of elements it gets attached to those elements and those elements only. If you add new elements to the DOM which would have been matched by the selector then they don't have the event handler bound to them (are you following me?) then nothing will happen. When using event delegation you can add as many matching elements to the DOM as you like after the event is bound and they work too.

Use classes to store state

This is the most basic way of storing information about a block of html. jQuery is great at manipulating elements based upon their classes, so if you need to store information about the state of an element then why not add an extra class to store it?
Here's an example. We want to create an expanding menu. When you click the button we want the panel to slideDown() if it's currently closed, or slideUp() if it's currently open. We'll start with the HTML
<div class="menuItem expanded">  
     <div class="button">  
         click me  
     </div>  
     <div class="panel">  
         <ul>  
             <li>Menu item 1</li>  
             <li>Menu item 2</li>  
             <li>Menu item 3</li>  
         </ul>  
     </div>  
</div>  

Very simple! We've just added an extra class to the wrapper div which serves no other purpose other than to tell us the state of the item. So all we need is a click event handler which performs slideUp() or slideDown() on the corresponding panel when the button is clicked.
$('.button').click(function() {  
   
     var menuItem = $(this).parent();  
     var panel = menuItem.find('.panel');  
   
     if (menuItem.hasClass("expanded")) {  
         menuItem.removeClass('expanded').addClass('collapsed');  
         panel.slideUp();  
     }  
     else if (menuItem.hasClass("collapsed")) {  
         menuItem.removeClass('collapsed').addClass('expanded');  
         panel.slideDown();  
     }  
});  
That's a very simple example, but you can add extra classes for storing all sorts of information about an element or HTML fragment.
However, in all but simple cases it's probably better to use the next tip.

Even better, use jQuery's internal data() method to store state

It's not very well documented for some reason but jQuery has an internal data() method which can be used to store information in key/value pairs against any DOM element. Storing a piece of data is as simple as this...
$('#myDiv').data('currentState', 'off');  
We can amend the example from the previous tip. We'll use the same HTML (with the "expanded" class removed) and use the data() function instead.
$('.button').click(function() {  
  
    var menuItem = $(this).parent();  
    var panel = menuItem.find('.panel');  
  
    if (menuItem.data('collapsed')) {  
        menuItem.data('collapsed', false);  
        panel.slideDown();    
    }  
    else {  
        menuItem.data('collapsed', true);  
        panel.slideUp();  
    }  
});  

Write your own selectors

$.extend($.expr[':'], {  
     over100pixels: function(a) {  
         return $(a).height() > 100;  
     }  
});  
   
$('.box:over100pixels').click(function() {  
    alert('The element you clicked is over 100 pixels high');  
});  
The first block of code creates a custom selector which finds any element that is more than 100 pixels tall. The second block just uses it to add a click handler to all those elements.
I won't go into any more detail here but you can imagine how powerful this is and if you search google for "custom jquery selector" you'll find loads of great examples.

Streamline your HTML and modify it once the page has loaded

<div class="fieldOuter">  
    <div class="inner">  
        <div class="field">This is field number 1</div>  
    </div>  
    <div class="errorBar">  
        <div class="icon"><img src="icon.png" alt="icon" /></div>  
        <div class="message"><span>This is an error message</span></div>  
    </div>  
</div>  
<div class="fieldOuter">  
    <div class="inner">  
        <div class="field">This is field number 2</div>  
    </div>  
    <div class="errorBar">  
        <div class="icon"><img src="icon.png" alt="icon" /></div>  
        <div class="message"><span>This is an error message</span></div>  
    </div>  
</div>
That's an example of how a form might be marked up, modified slightly for illustrative purposes. I'm sure you'll agree it's pretty ugly and if you had a long form you'd end up with a fairly long ugly page. It's be nicer if you could just put this in your HTML.
<div class="field">This is field 1</div>  
<div class="field">This is field 2</div>  
<div class="field">This is field 3</div>  
<div class="field">This is field 4</div>  
<div class="field">This is field 5</div>  
All you have to do is a bit of jQuery manipulation to add all the ugly HTML back in. Like this...
$(document).ready(function() {  
    $('.field').before('<div class="fieldOuter"><div class="inner">');  
    $('.field').after('</div><div class="errorBar"><div class="icon">  
        <img src="icon.png" alt="icon" /></div><div class="message">  
        <span>This is an error message</span></div></div></div>');  
});  
It's not always advisable to do this, you'll get a bit of a flash as the page loads, but in certain situations where you've got a lot of repeated HTML it can really reduce your page weight and the SEO benefits of reducing all your repeated extraneous markup should be obvious.

Lazy load content for speed and SEO benefits

Another way to speed up your page loads and neaten up the HTML that search spiders see is to lazy load whole chunks of it using an AJAX request after the rest of the page has loaded. The user can get browsing right away and spiders only see the content you want them to index.
$('#forms').load('content/headerForms.html', function() {  
     // Code here runs once the content has loaded  
     // Put all your event handlers etc. here.              
 });  
I wouldn't use this everywhere. You have to consider the trade offs here. You're making extra requests to the server and portions of your page might not be available to the user right away, but used correctly it can be a great optimization technique.

Use jQuery's utility functions

jQuery isn't just about flash effects. The creator has exposed some really useful methods which fill a few gaps in JavaScript's repertoire.
http://docs.jquery.com/Utilities
In particular, browser support for certain common array functions is patchy (IE7 doesn't even have an indexOf() method!). Jquery has methods for iterating, filtering, cloning, merging and removing duplicates from Arrays.
Other common functions that are difficult in Javascript include getting the selected item in a drop down list. In plain old JavaScript you'd have to get the <select> element using getElementByID, get the child elements as an array and iterate through them checking whether each one was selected or not. jQuery makes it easy...
$('#selectList').val(); 
It's worth spending some time looking through the jQuery documentation on the main site and having a nose around some of the lesser known functions.

Use noconflict to rename the jquery object when using other frameworks

Most javascript frameworks make use of the $ symbol as a shorthand and this can cause clashes when trying to use more than one framework on the same page. Luckily there's a simple solution. The .noconflict() function gives control of the $ back and allows you to set your own variable name, like this...
var $j = jQuery.noConflict();  
 $j('#myDiv').hide();  

How to tell when images have loaded

This is another one of those problems that doesn't seem to be as well documented as it should be (not when I went looking anyway) and it's a fairly common requirement when building photo galleries, carousels etc, but it's fairly easy.
All you have to do is use the .load() method on an IMG element and put a callback function in it. The following example changes the "src" attribute of an image tag to load a new image and attaches a simple load function.
$('#myImage').attr('src', 'image.jpg').load(function() {  
    alert('Image Loaded');  
}); 
You should find that the alert is called as soon as the image is loaded.

Wait for the final installment of this tutorial in Part-3. Till then enjoy the cool tips of this tutorial.

Written by

Arvind is a web developer, programmer and blogger. He has expertise in PHP, Magento, WordPress, jQuery, JavaScript, HTML5 and CSS3. He loves to develop good looking websites with strong backend.

0 comments :

Post a Comment

We would love to hear from you...

 

© 2014 Web Speaks . All rights resevered. Designed by Templateism