zithromax online

Upgrading jQuery – from 1.4.x to 1.6.x

The jQuery library, specifically its architecture of Ajax handling, has been significantly re-written in 1.5. We at Box love jQuery, but we had to skip version 1.5 because a quick jquery.js file replacement failed many of our automated test cases.

After a couple of weeks of debugging, we finally migrated to version 1.6.1. In this post, I want to share my experience upgrading jQuery from 1.4.4 to 1.6.1.

prop() and attr()

prop() is a new method to retrieve a property value of a DOM object, while attr() is used to retrieve attribute values written in the HTML source.

attr() used to be the single method to handle both cases. Basically, in jQuery 1.4, attr() first checks if the attribute is explicitly written in the HTML code, then it looks at the object created by the HTML tag, and inspects its object property. When you upgrade to newer versions of jQuery, you may need to change attr() to prop().

In our code, we had something like this

1
2
3
4
5
$('form').each(function() {
if ($(this).attr('method').toLowerCase() == 'post') {
// do something
}
});

This code used to work in 1.4.x, but it fails in 1.6.1. I then found out it fails on this case:

1
<form action="process.php"></form>

The problem is that, in 1.4, when a form has no method attribute written in the HTML code, it would return an empty string because method is a property, which happens to be an empty string, of the form object. However, in 1.6.1, the attr(“method”) call would return undefined because it is not written in the HTML code, and so doing toLowerCase() on undefined triggers error.

To fix the issue, we changed attr() to prop():

1
2
3
4
5
$('form').each(function() {
if ($(this).prop('method').toLowerCase() == 'post') {
// do something
}
});

According to the documentation, prop() should return undefined for the value of the property that has not been set. In reality, this is not true when doing prop(‘method’) on a form. As previously stated, “method” is a property of a form object even if it’s not explicitly written in the HTML code.

This is not the end of the story. It turned out that the JavaScript block shown above still fails in a form that looks like this:

1
<form action="action.php" method="post"><!-- a bunch of input fields --> <input type="ratio" name="method" value="xml" />XML <input type="ratio" name="method" value="json" />JSON</form>

And when we do $(‘form’).prop(‘method’), instead of returning the string “post”, it returns two input elements! The reason, which should be obvious, is because there are two input fields that are named “method.” As a result, we need to add to the coding practice that no input elements should be named “method.”

You now probably see some of the benefits of separating prop() and attr(). In addition to clearing confusion between HTML attributes and DOM element properties, there are a few more benefits using prop() when it’s applicable:
- From John Resig: “Accessing properties through the .attr() method will be slightly slower than accessing them directly through .prop() (as .attr() calls .prop() internally in order to handle all property-related mutation)”
- Attributes like ‘checked’ and ‘value’ of input elements do not map to their corresponding properties in the DOM elements. So doing attr(‘checked’) or attr(‘value’) will only retrieve the default/ initial value, but not the current one. You browser uses the property, and not the attribute, to keep track of the current value. That is also the reason why in previous versions we had to do :is(‘checked’) and .val(). Now that we have prop() and we can rely on it in getting the current value.
- In previous versions of jQuery, both attr(‘checked’, true) and attr(‘checked’, ‘checked’) would work. When examining the value, we have to look for every possible values. Using prop, we are sure it would return boolean for things like ‘checked’ and ‘readOnly.’

If you still find it confusing, visit http://www.timmywillison.com/2011/When-to-use-.attr()-and-.prop().html for a list of recommended usage.

Ajax and parseJSON

In the Box app, we use $.ajaxPrefilter to handle Ajax calls that are supposed to return a JSON object. Our unique approach is that the backend actually returns what we called BOXON (BOX Object Notation) strings, and we use ajaxPrefilter to convert BOXON to JSON by modifying the string and calling eval(). In then becomes a JavaScript object.

This no longer works in jQuery 1.6.1 (and probably 1.5+). Basically, the new Ajax architecture in jQuery would call $.parseJSON() after ajaxPrefilter. Here is the first few lines of $.parseJSON():

1
2
3
4
5
6
7
parseJSON: function( data ) {
if ( typeof data !== "string" || !data ) {
return null;
}
//...
// convert the "data" string into an object and return that
}

Because data, when coming from our own ajaxPrefilter, is already an object, the JSON object becomes null after parseJSON, and thus the Ajax calls get a null value to work on.

To fix this issue, I had to patch the jQuery code like this:

1
2
3
4
5
6
parseJSON: function( data ) {
if ( typeof data == "object" ) return data; /* true for both Array and Object */
if ( typeof data !== "string" || !data ) {
return null;
// ...
}

getAttribute on Flash objects

We also got a weird bug that occurred in IE9 only. After we moved to 1.6.1, the “upload” button won’t work!

After some investigation, I found that it’s related to our very own upload approach. We use HTML5 upload on browsers that support it. IE9 is not one of those browsers, and so we use a SWF object to handle it. Somewhere in the code, it triggers a click event on the SWF object that checks for $.(e.target).attr(‘id’) == ‘something’. SWF objects do not implement the getAttribute() DOM method, and so it fails.

This is such a race case and probably will not be seen in your application. A quick fix I added to the code is to return immediately in the custom mousedown/ click function if the target does not implement the .getAttribute method.

Plugins

Many popular jQuery plugins have to be upgraded to become compatible with the latest version of jQuery. For example, The jQuery Form plugin needs to be upgraded to 2.80. One of the reasons is that jQuery has removed the internal $.httpData() method since version 1.5. Plugins that make use of these methods need to be rewritten.

The jQuery validation plugin is another plugin that needs an upgrade. It works perfectly once we upgrade it to the latest version of 1.8.

Sweet, now we’re on the new train!

I am very happy about the new version of jQuery. In addition to the aforementioned new Ajax architecture (which brings good stuff like “deferred“), there are performance improvements (also see http://bugs.jquery.com/ticket/7341. Now I don’t have to modify the Sizzle engine to make it faster in IE!), and a lot of nice fixes and features. If you have not upgraded yet due to compatibility issues like the ones described above, I suggest you to take some time to do some investigation and adjust the code. Don’t stay behind and miss out the good things the new version of jQuery brings to the table.

You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.
4 Responses
  1. wimc says:

    You rock!

    I was trying to run a spinbox that was designed for jQuery 1.4.2 (http://askthecssguy.com/examples/tapbox/test.html) but it failed to respond.

    Until I found your article about the new prop() method. Changed the 3 instances calling prop in the js and voila!

    Thanks!

  2. Magnus says:

    Thanks for this nice writeup :-) I changed from attr() to prop() in 2 locations.

  3. [...] David Tong – Upgrading jQuery – from 1.4.x to 1.6.x [...]

  4. Yuga says:

    Thanks a lot for an useful article.

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>