Updates with jQuery 1.6.1

Updated jeffcogswell 2 Tallied Votes 572 Views Share
Manufacturer
jQuery
URL Screenshot of http://www.jquery.com http://www.jquery.com
Price
Free / Open Source
Pros
Some nice changes including to performance
Cons
Some earlier code might break and you might have to fix earlier code
Summary
The newest version of jQuery contains lots of enhancements. Some of the changes might break earlier code, however. But all-in-all, the improvements are good and help improve an already excellent product.
Rating

I've been using jQuery for a few years now, and the more I use it, the more I like and appreciate it. It seems like I'm always finding new ways to use it, and usually those new techniques result in me writing less code and ultimately being more productive. On May 3, jQuery 1.6 was released; then almost immediately, on May 12, came a new patch for this major release called 1.6.1.

The 6.1 release included a major change to the way jQuery handles attributes, and a lot of people were upset about the change, as it had the potential to break earlier code. But the jQuery team heard the gripes (unlike a certain giant company called Facebook), and responded by fixing it, allowing you to continue using jQuery the way you had before, while also allowing for a new way of using it with what are called properties. In this review, I'm going to look at that in more detail.

But first, speaking of updates breaking older code, I've seen people online ask how to write their code so that their HTML files always include the latest and greatest jQuery, without hardcoding a particular version. My response has always been that that's a bad idea, and the release of 1.6 shows just why that is: If you wrote some JavaScript code to always include the latest and greatest jQuery, and you have that code live on production server, there's a possibility that your site would have broken when 1.6 was released. But if you had hardcoded the version that you know works with your code, then the release would not have impacted your site, and you would have had an opportunity to test your site against the new version before going live with it. That's why it's generally not a good idea to automatically pick up the latest version of jQuery. (But as is always the case in software development, every rule has exceptions, and you might have a good reason to do otherwise.)

Now let's look at some of the new features. I'm assuming here that you're already familiar with how to use jQuery.

Properties vs Attributes

Now that 6.1 and 6.1.1 are out, I'm surprised most of us didn't even realize that the code we were writing had a small problem with it. Think about the following HTML:

This code displays a checkbox on the page that's initially checked. In your JavaScript code, you can determine the state of the checkbox at any time by looking at the checked attribute. And therein lies the problem. With earlier versions of jQuery, you might use this code:

var x = $('#check1').attr('checked');
console.log(x);

Then in the console, you'll see the value true. But is that really the value of the checked attribute? If you look at the HTML, you can see the value of the checked attribute is the string 'checked', not the value true.

In general, this didn't cause a problem for most people, since if you wanted to know if the checkbox was checked, it made logical sense for the checked attribute to give you back a value of true or false. But technically, that's not what's in the attribute: The attribute contains the literal string 'checked'. And so the designers of jQuery decided to clarify this and give us two different ways to tackle this: We can look at the checked attribute and get its actual value (in this case 'checked'), or we can use what's called a property, which, in the case of the checked property, will give us a value of true or false, which is more in line with what we're looking for.

In other words, this forces us to be aware of two things: the actual underlying element, and the jQuery object representing the object. And so with jQuery 1.6 (not 1.6.1 yet, though), you'll get back something different from what you would have before with the same code:

var x = $('#check1').attr('checked');
console.log(x);

The console in this case will show the word checked, not true. Here's the output from two different Chrome debugger windows, one with jQuery version 1.5.2, and the other version 1.6.0:

But things got even weirder. What if you uncheck the box? Well, in version 1.6.0, the attribute hasn't changed and still gives you 'checked'. Here's the output from the Chrome debugger; in the first two lines the checkbox was checked initially; then I unchecked it and ran the code again for the second two lines.

In both cases it gives me the word 'checked'. There's actually a good technical reason for that regarding W3C standards, but, as you can imagine, that's kind of nightmarish, especially if you were planning to do something like this (which worked in earlier versions):

if ($('#check1').attr('checked') == true) {
    alert('checked!');
}

The solution in version 1.6.0 is to stop using attr() in this situation and instead use prop(). Here's the revised code:

var x = $('#check1').prop('checked');
console.log(x);

This code gives me a value of true or false.

But guess what! People were understandably upset about the changes to attr(). And so the jQuery team quickly issued a patch and now attr() works similarly to the way it used to. That means your earlier code shouldn't break. At least in theory it shouldn't. But in my tests, I discovered that it's not actually identical to the way it used to be. Now the attr('checked') call will return 'checked' if the checkbox is checked, and undefined if the checkbox isn't checked. That means that this code still won't work correctly in version 1.6.1:

if ($('#check1').attr('checked') == true) {
    alert('checked!');
}

But this code, will work correctly in both version 1.6.1 and earlier versions not including 1.6.0. Notice I removed the == true part:

if ($('#check1').attr('checked')) {
    alert('checked!');
}

Now my guess is that most people probably write the second version, leaving off the ==true part. But not me; I always include the ==true so that my code is more readable. But realistically, I'm okay with that, because if I'm going to update my code to work with version 1.6.1, I'll probably want to start using prop() anyway. But I'm going to have to do a full pass through all my code before updating, and make sure I made the necessary changes everywhere.

The take-home message here, then, is that if you're going to upgrade to the latest version, first, don't use 1.6.0; instead go right to 1.6.1. And second, make sure you understand the difference between attr and prop, and start using prop when you can.But wait there's more with the attributes

There are actually a couple more smaller changes to the way attributes work. I personally haven't used this feature, but it's there if you need it, and, unfortunately, some earlier code could break. But this seems to be a rare usage. It turns out that you can include attributes in your HTML that start with the word data- (followed by a hyphen) and those attributes will automatically get read in as data on the element. You can then access these through the data() function. This feature has actually existed since 1.5. However, the way it was implemented was apparently not in conformance with a W3C specification. Look at this input element, and notice the final attribute, data-my-info:

With jQuery 1.5.2, you could access the data-my-info attribute through the data function like this:

var myInfo = $('#check1').data('my-info');
console.log(myInfo);

In this case the value is 10, since that's the value in the HTML.

The name of the data item is the name of the attribute without the data- part, or my-info. But now version 1.6.1 changes that, and you have to adjust your code a bit, making the name what they call “camel case”, like so:

var myInfo = $('#check1').data('myInfo');
console.log(myInfo);

Now, the name is myInfo rather than my-info. So again, if you used this feature, you'll have to adjust your code with the new version.Improvements to .map()

The .map() function has improved, and fortunately this one won't break older code; it's an enhancement to the function. With previous versions of jQuery, the .map function was already pretty cool, and definitely useful. Here's how it works. Suppose you have an array like so:

var a = [1,2,3];

If you call $.map, you can create a new array where you calculate the elements individually in the new array based on the elements from the existing array. Here's an example. Look at this function:

$.map(a, function(item) {
    return item * 2;
});

You call $.map, and pass the original array, in this case a, or [1,2,3]. You also pass a function. jQuery will call that function for each element in the array. What this function returns gets put in the new array. The function in this example just returns a value times two, so the resulting array will look like this:

[2, 4, 6]

The function you supply gets called for the first element in the original array (1), and the result (2) is put in the new array. Then it gets called on the second element (2) and the result (4) gets put in the new array, and so on.

But the elements in the array don't have to be numbers. They can be objects or anything, really. And you can write whatever function you want. Here's an example that creates an array of IDs of elements:

var elems = $('div');
var ids = $.map(elems, function(elem) {
    return $(elem).attr('id');
});
console.log(ids);

The original array contains the divs in the document. The resulting array contains the IDs. In my test HTML (not shown here), here's what I get:

["div1", "div2", "div3"]

This has always been useful, but now jQuery 1.6 takes it a step further: You can do the same thing with members of an object, not just elements of an array. At first, this might seem a bit odd, but the real power is when people use an object as an associative array (as is commonly done in JavaScript). Here's an example where I'm using an object as an associative array, and use map() to pull out just one member of each object into a new list. (This only works with 1.6 or higher.)

var items = { };
items['Jeff'] = { username:'jeffcogswell', last: 'Cogswell' };
items['Dani'] = { username:'cscgal', last: 'Horowitz' };
items['Eyal'] = { username:'WASDted', last: 'Akler' }

var newObj = $.map(items, function(elem) {
    return elem.last;
});
console.log(newObj);

Here's the result:

["Cogswell", "Horowitz", "Akler"]

Another useful feature is pulling out all the keys in the associative array. This is a common problem in JavaScript, and jQuery makes it easy. Continuing with the same previous example:

var keys = $.map(items, function(elem, key) {
    return key;
});

console.log(keys);

Here's the result:

["Jeff", "Dani", "Eyal"]

Of course, this problem is easily solved without jQuery:

var keys2 = [];
for (x in items) {
    keys2.push(x);
}

console.log(keys2);


Other Tidbits

Since this is considered a major release of jQuery, there's no shortage of updates. Here's a brief look at some more of them:

Relative CSS: You can now change CSS values relatively, which is handy for doing your own animations or live changes. The self-explanatory example they give in the docs is $("#item").css("left", "+=10px");. This increases the CSS left style by 10 pixels. That will save a few lines of code.

Smoother animations: Apparently there's an API in some browsers that lets you code better animations in JavaScript. jQuery now takes advantage of this.

Performance: Calls to .data() have improved, as have event triggering.

And speaking of performance, I want to throw in a final thought: As recent as just three or four years ago, performance was a huge issue in developing heavy client-side JavaScript code. I had developed some software that really struggled with some older browsers. While these problems might still exist in older browsers, with so many people finally updating to the modern browsers that include high-speed JavaScript engines, and with the help of performance increases in libraries like jQuery, we can finally develop client-side code that moves along as speedily as a desktop application. For me personally as a web developer, that is a huge plus, because I can finally develop the software I want to. So for me, any performance increases in jQuery alone make it a must-have for me.

almostbob commented: Thankyou +13
Steve Nelson 0 Newbie Poster

Who wrote this article? Do you also write JS code for this website?

jeffcogswell 175 Light Poster Featured Poster

I'm Jeff Cogswell, and I wrote the article. I don't have anything to do with the programming of this web site. Is there an error in the article? If so, let me know and I'll fix it. Thanks!

Steve Nelson 0 Newbie Poster

First of all, it's a helpful article. I don't have any experienced with Jquery, always wanted to learn it but never really needed to learn it. I do a lot of JavaScript coding, all without jQuery. Can you share any of the "Tricks" with jQuery you mentioned? It will be very useful for people like me that want to learn jQuery fast.
As for errors, yes, there are a few "not so good" coding practices here and there, no big deal, I just been writing JS for very long time and spot common mistakes right away. Not really an error but you should just always use === and !== instead of == and !=
Just make it a habit, you will become better JS coder just because of it. There are more things like that I see but not a big deal.

Airshow 416 WiFi Lounge Lizard Team Colleague

Jeff, nice article.

I just have to ask two questions.

Would the sentence "The original array contains the divs in the document" better read "The original jQuery object contains the divs in the document", or to be really picky, "The original jQuery object contains references to the divs in the document"?

Following this through (and with reference to Flanagan, jQuery Pocket Reference; O'reilly), might the sentence "You can do the same thing with members of an object, not just elements of an array" better read, "You can do the same thing with JavaScript objects, not just arrays, jQuery objects and other array-like objects"? Cumbersome but complete, I think.

Airshow

jeffcogswell 175 Light Poster Featured Poster

Steve, thanks for the tips! I can probably post some of my own jQuery tips here, and maybe others can too and see what we can come up with. (I'm on a tight deadline right now, but it would be fun to do that this weekend.)

Jeff

jeffcogswell 175 Light Poster Featured Poster

Hi Airshow,

Excellent, YES on all counts! You're absolutely correct. What I'm passing in is, in fact, a single jQuery object that contains a list of references. For that matter, I'm glad you brought that up, because it's easy for people new to jQuery to forget that the call jQuery() or $() returns a single object which in itself might contain a list. And that, of course, is how chaining like $('div').a().b().c() works.

Jeff

jeffcogswell 175 Light Poster Featured Poster

...in fact, a quick correction to my last comment, when I said "might" contain a list, in fact, it always contains a list; the list might contain only one element. --Jeff

Airshow 416 WiFi Lounge Lizard Team Colleague

Or no elements, vis $(); or $('nonExistentTag') ?

Airshow

jeffcogswell 175 Light Poster Featured Poster

Yes, good one! For the other people reading this thread who might be new to jQuery, what Airshow is saying is absolutely correct. When you call $() (which is shorthand for jQuery()) you get back a single object. That single object contains a list of references to elements that matched your selector. So, for example, if you call:

var x = $('div')

you'll get back what appears to be a list of all the divs in your document. In fact, what you're actually getting back is a single jQuery object that contains a list. That list holds references to your div elements, and that list might have zero items, one item, or many items depending on your document. Or if you call

var x = $('.MyClass')

then you'll get back what appears to be a list of all the elements in your document that have the class MyClass. (The dot in '.MyClass' means class.) But regardless of how many elements you have, you're actually always getting back a single jQuery object. The reason is that you can do further operations like this:

$('.MyClass').click(function() {
});

Conceptually, this calls the click function on each element that you get back, assigning the passed-in function as a click handler for each element. But in reality, you're calling the click function on the single jQuery object you get back: The $('.MyClass') call returns a single object, and that object has a member function called click. You're calling click on that single object, and that click function assigns a click handler to all the elements in the list.

Jeff

twiss 155 Veteran Poster

About the last example, you can also do this:

var keys2 = [], i = 0;
for (keys2[i++] in items) {}
console.log(keys2);
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.