Thursday, May 31, 2012

jQuery pitfalls to avoid


I am starting a project with jQuery.



What pitfalls/errors/misconceptions/abuses/misuses did you have in your jQuery project?



Source: Tips4all

28 comments:

  1. Being unaware of the performance hit and overusing selectors instead of assigning them to local variables. For example:-

    $('#button').click(function() {
    $('#label').method();
    $('#label').method2();
    $('#label').css('background-color', 'red');
    });


    Rather than:-

    $('#button').click(function() {
    var $label = $('#label');
    $label.method();
    $label.method2();
    $label.css('background-color', 'red');
    });


    Or even better with chaining:-

    $('#button').click(function() {
    $("#label").method().method2().css("background-color", "red");
    });


    I found this the enlightening moment when I realized how the call stacks work.

    Edit: incorporated suggestions in comments.

    ReplyDelete
  2. Don't use bare class selectors, like this:

    $('.button').click(function() { /* do something */ });


    This will end up looking at every single element to see if it has a class of "button".

    Instead, you can help it out, like:

    $('span.button').click(function() { /* do something */ });
    $('#userform .button').click(function() { /* do something */ });


    I learned this last year from Rebecca Murphy's blog

    Update - This answer was given over 2 years ago and is not correct for the current version of jQuery.
    One of the comments includes a test to prove this.
    There is also an updated version of the test that includes the version of jQuery at the time of this answer.

    ReplyDelete
  3. Understand how to use context. Normally, a jQuery selector will search the whole doc:

    // This will search whole doc for elements with class myClass
    $('.myClass'); //


    But you can speed things up by searching within a context:

    var ct = $('#myContainer');
    // This will search for elements with class myClass within the myContainer child elements
    $('.myClass', ct);

    ReplyDelete
  4. Avoid abusing document ready.
    Keep the document ready for initialize code only.
    Always extract functions outside of the doc ready so they can be reused.


    I have seen hundreds of lines of code inside the doc ready statement. Ugly, unreadable and impossible to maintain.

    ReplyDelete
  5. While using $.ajax function for Ajax requests to server, you should avoid using the complete event to process response data. It will fire whether the request was successful or not.

    Rather than complete, use success.

    See Ajax Events in the docs.

    ReplyDelete
  6. Try to split out anonymous functions so you can reuse them.

    //Avoid
    $('#div').click( function(){
    //do something
    });

    //Do do
    function divClickFn (){
    //do something
    }

    $('#div').click( divClickFn );

    ReplyDelete
  7. "Chaining" Animation-events with Callbacks.

    Suppose you wanted to animate a paragraph vanishing upon clicking it. You also wanted to remove the element from the DOM afterwards. You may think you can simply chain the methods:

    $("p").click(function(e) {
    $(this).fadeOut("slow").remove();
    });


    In this example, .remove() will be called before .fadeOut() has completed, destroying your gradual-fading effect, and simply making the element vanish instantly. Instead, when you want to fire a command only upon finishing the previous, use the callback's:

    $("p").click(function(e){
    $(this).fadeOut("slow", function(){
    $(this).remove();
    });
    });


    The second parameter of .fadeOut() is an anonymous function that will run once the .fadeOut() animation has completed. This makes for a gradual fading, and a subsequent removal of the element.

    ReplyDelete
  8. Pitfall: Using loops instead of selectors.

    If you find yourself reaching for the jQuery '.each' method to iterate over DOM elements, ask yourself if can use a selector to get the elements instead.

    More information on jQuery selectors:
    http://docs.jquery.com/Selectors

    Pitfall: NOT using a tool like Firebug

    Firebug was practically made for this kind of debugging. If you're going to be mucking about in the DOM with Javascript, you need a good tool like Firebug to give you visibility.

    More information on Firebug:
    http://getfirebug.com/

    Other great ideas are in this episode of the Polymorphic Podcast:
    (jQuery Secrets with Dave Ward)
    http://polymorphicpodcast.com/shows/jquery/

    ReplyDelete
  9. Don't abuse plug-ins.

    Most of the times you'll only need the library and maybe the user interface. If you keep it simple your code will be maintainable in the long run. Not all plug-ins are supported and maintained, actually most are not. If you can mimic the functionality using core elements I strongly recommend it.

    Plug-ins are easy to insert in your code, save you some time, but when you'll need an extra something, it is a bad idea to modify them, as you lose the possible updates. The time you save at the start you'll loose later on changing deprecated plug-ins.

    Choose the plug-ins you use wisely.
    Apart from library and user interface, I constantly use $.cookie , $.form, $.validate and thickbox. For the rest I mostly develop my own plug-ins.

    ReplyDelete
  10. 10 Ways to Instantly Increase Your jQuery Performance

    Check this article.

    ReplyDelete
  11. If you bind() the same event multiple times it will fire multiple times . I usually always go unbind('click').bind('click') just to be safe

    ReplyDelete
  12. Misunderstanding of using this identifier in the right context. For instance:

    $( "#first_element").click( function( event)
    {
    $(this).method( ); //referring to first_element
    $(".listOfElements").each( function()
    {
    $(this).someMethod( ); // here this is not referring first_element anymore.
    })
    });


    And here one of the samples how you can solve it:

    $( "#first_element").click( function( event)
    {
    $(this).method( ); //referring to first_element
    var $that = this;
    $(".listOfElements").each( function()
    {
    $that.someMethod( ); // here this is not referring first_element anymore.
    })
    });

    ReplyDelete
  13. Avoid multiple creation of the same jQuery objects

    //Avoid
    function someFunc(){
    $(this).fadeIn();
    $(this).fadeIn();
    }

    //Cache the obj
    function someFunc(){
    var $this = $(this).fadeIn();
    $this.fadeIn();
    }

    ReplyDelete
  14. Similar to what Repo Man said, but not quite.

    When developing ASP.NET winforms, I often do

    $('<%= Label1.ClientID %>');


    forgetting the # sign. The correct form is

    $('#<%= Label1.ClientID %>');

    ReplyDelete
  15. Events

    $("selector").html($("another-selector").html());


    doesn't clone any of the events - you have to rebind them all.

    As per JP's comment - clone() does rebind the events if you pass true.

    ReplyDelete
  16. Always cache $(this) to a meaningful variable
    especially in a .each()

    Like this

    $(selector).each(function () {
    var eachOf_X_loop = $(this);
    })

    ReplyDelete
  17. Avoid searching through the entire DOM several times. This is something that really can delay your script.

    Bad:

    $(".aclass").this();
    $(".aclass").that();
    ...


    Good:

    $(".aclass").this().that();


    Bad:

    $("#form .text").this();
    $("#form .int").that();
    $("#form .choice").method();


    Good:

    $("#form")
    .find(".text").this().end()
    .find(".int").that().end()
    .find(".choice").method();

    ReplyDelete
  18. I say this for JavaScript as well, but jQuery, JavaScript should NEVER replace CSS.

    Also, make sure the site is usable for someone with JavaScript turned off (not as relevant today as back in the day, but always nice to have a fully usable site).

    ReplyDelete
  19. Using ClientID to get the "real" id of the control in ASP.NET projects.

    jQuery('#<%=myLabel.ClientID%>');


    Also, if you are using jQuery inside SharePoint you must call jQuery.noConflict().

    ReplyDelete
  20. Passing IDs instead of jQuery objects to functions:

    myFunc = function(id) { // wrong!
    var selector = $("#" + id);
    selector.doStuff();
    }

    myFunc("someId");


    Passing a wrapped set is far more flexible:

    myFunc = function(elements) {
    elements.doStuff();
    }

    myFunc($("#someId")); // or myFunc($(".someClass")); etc.

    ReplyDelete
  21. Excessive use of chaining.

    See this:

    this.buttonNext[n ? 'bind' : 'unbind'](this.options.buttonNextEvent, this.funcNext)[n ? 'removeClass' : 'addClass'](this.className('jcarousel-next-disabled')).attr('disabled', n ? false : true);


    Explanation

    ReplyDelete
  22. my two cents)

    Usually, working with jquery means you don't have to worry about DOM elements actual all the time. You can write something like this - $('div.mine').addClass('someClass').bind('click', function(){alert('lalala')}) - and this code will execute without throwing any errors.

    In some cases this is useful, in some cases - not at all, but it is a fact that jquery tends to be, well, empty-matches-friendly. Yet, replaceWith will throw an error if one tries to use it with an element which doesn't belong to the document. I find it rather counter-intuitive.

    Another pitfall is, in my opinion, the order of nodes returned by prevAll() method - $('<div><span class="A"/><span class="B"/><span class="C"/><span class="D"/></div>').find('span:last-child').prevAll(). Not a big deal, actually, but we should keep in mind this fact.

    ReplyDelete
  23. Making too many DOM manipulations. While the .html(), .append(), .prepend(), etc. methods are great, due to the way browsers render and re-render pages, using them too often will cause slowdowns. It's often better to create the html as a string, and to include it into the DOM once, rather than changing the DOM multiple times.

    Instead of:

    var $parent = $('#parent');
    var iterations = 10;

    for (var i = 0; i < iterations; i++){
    var $div = $('<div class="foo-' + i + '" />');
    $parent.append($div);
    }


    Try this:

    var $parent = $('#parent');
    var iterations = 10;
    var html = '';

    for (var i = 0; i < iterations; i++){
    html += '<div class="foo-' + i + '"></div>';
    }

    $parent.append(html);


    Or even this ($wrapper is a newly created element that hasn't been injected to the DOM yet. Appending nodes to this wrapper div does not cause slowdowns, and at the end we append $wrapper to $parent, using only one DOM manipulation):

    var $parent = $('#parent');
    var $wrapper = $('<div class="wrapper" />');
    var iterations = 10;

    for (var i = 0; i < iterations; i++){
    var $div = $('<div class="foo-' + i + '" />');
    $wrapper.append($div);
    }

    $parent.append($wrapper);

    ReplyDelete
  24. If you want users to see html entities in their browser, use 'html' instead of 'text' to inject a Unicode string, like:

    $('p').html("Your Unicode string")

    ReplyDelete
  25. Use strings accumulator-style

    Using + operator a new string is created in memory and the concatenated value is assigned to it. Only after this the result is assigned to a variable.
    To avoid the intermediate variable for concatenation result, you can directly assign the result using += operator.
    Slow:

    a += 'x' + 'y';


    Faster:

    a += 'x';
    a += 'y';


    Primitive operations can be faster than function calls

    Consider using alternative primitive operation over function calls in performance critical loops and functions.
    Slow:

    var min = Math.min(a, b);
    arr.push(val);


    Faster:

    var min = a < b ? a : b;
    arr[arr.length] = val;


    Read More at JavaScript Performance Best Practices

    ReplyDelete
  26. If you plan to Ajax in lots of data, like say, 1500 rows of a table with 20 columns, then don't even think of using jQuery to insert that data into your HTML. Use plain JavaScript. jQuery will be too slow on slower machines.

    Also, half the time jQuery will do things that will cause it to be slower, like trying to parse script tags in the incoming HTML, and deal with browser quirks. If you want fast insertion speed, stick with plain JavaScript.

    ReplyDelete
  27. Not understanding event binding. JavaScript and jQuery work differently.

    By popular demand, an example:

    In jQuery:

    $("#someLink").click(function(){//do something});


    Without jQuery:

    <a id="someLink" href="page.html" onClick="SomeClickFunction(this)">Link</a>
    <script type="text/javascript">
    SomeClickFunction(item){
    //do something
    }
    </script>


    Basically the hooks required for JavaScript are no longer necessary. I.e. use inline markup (onClick, etc) because you can simply use the ID's and classes that a developer would normally leverage for CSS purposes.

    ReplyDelete
  28. Using jQuery in a small project that can be completed with just a couple of lines of ordinary JavaScript.

    ReplyDelete