jQuery 1.6 and 1.6.1 are out the door. Congrats to the team and everyone that was involved with the release!
A relatively controversial change in 1.6 was regarding how attributes and DOM object properties were handled. In 1.6 we wanted to take the major step of completely separating the two, allowing us to create an .attr()
method that wasn’t quite so mealy-mouthed with regards to how attributes were handled. We did this in 1.6 because we felt that it was a substantial change (we only do major changes in the 1.x major releases of jQuery) and had the possibility of affecting people.
We did a considerable amount of testing on the code and we were quite confident that the amount of problems that people would encounter, while upgrading, would be quite minimal. The biggest pain points, we surmised, would be regarding how boolean attributes were handled (attributes like “disabled” or “selected”). However most of this would be mitigated and would likely have worked fine for users that consistently used .attr()
to access and update their attributes.
After making the changes, and publishing 1.6, there were enough complaints that we had changed the API to cause us to reconsider and return .attr()
to its sometimes-attribute, sometimes-property, state.
jQuery is in an incredibly tricky position now (and has been for some time). We very rarely add features to the library, for fear of bloat and added API maintenance overhead, and are rarely able to make any sort of API change, for fear of preventing people from upgrading.
Thankfully even though we’ve reverted some of the changes in 1.6, we’ve done it in a way that still maintains the performance gains that we achieved with the 1.6 release.
I wanted to try and summarize the .attr()
method, to explain how it currently works in 1.6.1, but ended up writing up a sample function instead (note that this is a bit of an over-simplification, please read the code for more details):
function attr( elem, name, value ) { // Are we setting a value? if ( value !== undefined ) { // Make sure the element has the ability to set an attribute if ( typeof elem.setAttribute !== "undefined" ) { // If the user is setting the value to false if ( value === false ) { // Completely remove the attribute elem.removeAttribute( name ); // Otherwise set the attribute value } else { // If the user is setting the value to true, // Set it equal to the name of the attribute // (handles boolean attributes nicely) elem.setAttribute( name, value === true ? name : value ); } // If it doesn't, then we're likely dealing with window or document // (or some other object entirely) } else { elem[ name ] = value; } // Otherwise we're getting an attribute value // Check to see if the appropriate method exists // Also don't use getAttribute if a boolean property exists } else if ( typeof elem.getAttribute !== "undefined" && typeof elem[ name ] !== "boolean" ) { return elem.getAttribute( name ); // If no getAttribute method is present, or if we // wish to access the boolean property instead of the // attribute, then we fallback to the DOM object property } else { return elem[ name ]; } }
Ironically this isn’t much shorter than the actual .attr()
implementation, I recommend that you check it out.
There’s a very good chance that your code, written targeting 1.5.2, will continue to work just fine in 1.6.1 using this particular technique.
However this point now begs the question: Why does .prop() exist?
In short, for two reasons:
- There are legitimate use cases for interacting with some DOM properties (such as
nodeName
,selectedIndex
, ordefaultValue
) and we want to provide a simple solution for accessing, and mutating, them. - 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).
In jQuery 1.5.2, and older, in order to access a DOM property you would have to do something like this:
var elem = $("#foo")[0]; if ( elem ) { index = elem.selectedIndex; }
In 1.6+ you can just do:
index = $("#foo").prop("selectedIndex");
Summary: There’s a good chance that your code won’t be affected at all with the changes that’ve happened, especially so with the changes in 1.6.1, and jQuery now has a convenience method for handling DOM properties in a simpler, and slightly faster, manner.
Tangentially this reminds me of a common question that I hear: What will be in jQuery 2.0? I have no idea what will be in that release, should it ever arrive, but I do know what won’t be in it: A massive API change of any sort. Even when we make, relatively minor, API changes like in the 1.6 release the amount of negative feedback that we get is monumental. If we’ve learned anything after doing 31 releases of jQuery it’s that people like having stability in their API and will cherish that over everything else.
I do want to thank the community though for being so vocal and working to communicate with the team so actively. Without the community’s communication and support it’s doubtful that the team would be able to continue operating.
I would like to take this opportunity to encourage everyone to get involved with the development of jQuery. We hold active discussions every day in IRC and hold public meetings once a week. We also post weekly status updates if you wish to follow along. Right now we’re working on the 1.7 release of the library and are actively encouraging contributions and feedback. If you want to help ensure the quality and stability of the next release of jQuery, the best way to do so is to get involved. Hope to see you around the bug tracker.
Travis (May 13, 2011 at 9:12 am)
Don’t let the voices of those who are afraid of change slow innovation.
If you were to make large API changes in a jQuery 2.0 release there would be nothing stopping someone from using 1.6.1!
Neal (May 13, 2011 at 9:14 am)
Thank you so much for the change!
I was going a bit crazy trying to figure out if I was going to have to change all of my
attr()
withprop()
calls.~Neal
Lucatoni (May 13, 2011 at 9:15 am)
Big misstake to revert in 1.6.1. People are to lazy to read changelog and do search and replace but they have to upgrade on the same freaking day of the release! Damn curled kids. Grow up or I’ll bet you all back to the times before php, with nasty perl code bitchslapping you in your cgi face. Ill tell you upgrading something in those times where not a matter of drag and drop to replace some file kids!
Marco Pivetta (May 13, 2011 at 9:19 am)
Well, jQuery 1.6 broke some stuff also in my case, but I think it’s to the devs (me) to fix that, not you. You provide great stuff, and I’m only thankful for what you and the jQuery team do.
Everybody should follow the API and try updating and fixing as much as possible (sharing what bugs have been spotted and their patches, obviously).
1.7 will probably not be that different from 1.6, but you shouldn’t fear the end users. That’s what release versioning is for!
Personally, I’m for inclusion of stuff in the jQuery repository (some kind of way Symfony does). Not in core, but in some “officially supported” repo.
With that, a better script loader would be really great! Something that removes the evil document.write forever :D
timmywil (May 13, 2011 at 9:19 am)
Nice post John!
Jeff (May 13, 2011 at 9:22 am)
I haven’t had a chance to really look at the changes yet but I will say this. If this is the best thing for the performance and usability of the library, then I am all for it. If not, and it’s just due to the negativity and lack of ambition on the parts of those who don’t want to really learn how to use JavaScript and jQuery, then I think that’s a loss for the rest of us.
I think what some people still don’t understand is that jQuery is a tool to help them enhance their websites, NOT to hold their hands and magically build it for them. Plus, it’s free people. So until you contribute to the community or pay for it, maybe you should stop whining, roll up your sleeves and do your homework to build yourself a better website.
ctrlShiftBryan (May 13, 2011 at 9:24 am)
Couldn’t you make a new attribute only function and depreciate the old one? Something like ‘.attb’ to go along with ‘.prop’
David Parker (May 13, 2011 at 9:36 am)
Great work and great post John. Although I’d agree with the people who say that it’s up to the devs to make their changes to their code according to your APIs. That said, I wouldn’t make major changes except on the 2.0, 3.0, etc. In the meantime, you could deprecate certain code and let the devs know about it well in advance.
Ben Barber (May 13, 2011 at 9:52 am)
Thanks for posting this John. I’ve been curious of your perspective on the fallout of 1.6.
Why did you choose to add API compatibility in 1.6.1 instead of providing a compatibility plugin as you’ve done for 1.4 and other releases? I’m sure this was considered, so I’m curious what the rationale was for adding backwards compatibility in 1.6.1.
For the record, I agree that jQuery’s backwards compatibility is critical to jQuery’s continued success. The proliferation of plugins create a complex, potentially unresolvable dependency graph if there are incompatible jQuery versions.
Slappy (May 13, 2011 at 9:57 am)
Personally i am glad you reverted. The attr change was a little too big. Had you swapped the attr and prop functions (not names) I would agree. However the potential for broken code was a little too great in 1.6. You need to bear in mind non greenfield apps wishing to take advantage of upgrades without changes to code base. Isnt this the sum totalselling point of a library?
I believe you are starting to suffer from Microsoft syndrome. Trying to be everything to everyone is not an easy task.
Jon Howard (May 13, 2011 at 10:01 am)
The users need to know what they are upgrading before they upgrade. Making beneficial changes is a must in any development environment. It’s up to us to upgrade with caution and understand what we are getting into. Great work on making jQuery better. Looking forward to whatever else is in store.
Tim Down (May 13, 2011 at 10:23 am)
I’ve been critical on Hacker News about the messages coming from the jQuery team about both 1.6 and 1.6.1, so thank you for taking the time to explain your reasoning. However… some questions:
1) Why are you recommending attr() over prop(), and hence apparently attributes over properties? Properties are the way to go, as you well know.
2) Apart from the performance boost, how is the current situation (two methods rather than one with no clear rationale for which one should be used) better than the previous situation?
3) The consequences (lots of sites breaking when trying to upgrade) of the attr/prop change in 1.6 were obvious but conceptually it was the right way to go. It now looks like you’ve bottled it. Have you been pressured by users to revert the 1.6 change?
michael ossareh (May 13, 2011 at 10:33 am)
I recently got bitten by .attr() on 1.5.1;
<ul>
<li id="foo" for="someid">
…
</ul>
$(‘foo’).attr(‘for’) is undefined in this case. Changing for to, say, target in the dom and the attr call returns ‘someid’. Am I falling foul of some dom-correctness-jazz?
Tim Down (May 13, 2011 at 10:47 am)
Michael: No, “for” is not a valid attribute for an element and as a result, adding a “for” attribute will not be reflected as a property called “for” in most browsers. Furthermore, “for” is a reserved word in JavaScript meaning that it cannot be used as an object property name. attr() uses properties in most cases prior to 1.6, hence your problem. Since the attribute is not valid, you shouldn’t really expect any particular behaviour anyway.
Prestaul (May 13, 2011 at 11:06 am)
While I agree with most of the commenters that say we cannot halt progress for the sake of compatibility, I was one of those opposed to the API change when 1.6 hit. I’m happy to update my code (this is not a difficult refactor) but I think some of the distaste for the change came from the fact that the incompatibility was so poorly communicated. If there had been a better communication of which code would be at risk and what the update path was then you would have seen much less opposition.
Tim Down (May 13, 2011 at 11:08 am)
I take that back: you can use “for” as a property name, just not as an identifier.
jQuery Agentur (May 13, 2011 at 11:20 am)
Ok…i wrote here for about 15 minutes, but in the end this is the essence:
People are happy because jQuery is great – yes!
jQuery is great because you do what makes the people happy – no.
Andrew Dupont (May 13, 2011 at 11:47 am)
Tim, your first response to Michael doesn’t make sense to me. Where is it written that
attr
only works with valid attribute names? That’s not a requirement of the DOM —getAttribute('blerg')
will happily retrieve whatever value you’ve defined forblerg
.James Sumners (May 13, 2011 at 12:55 pm)
Here’s a thought, issue deprecation warnings on an API _before_ it changes.
David B (May 13, 2011 at 12:59 pm)
Any thought to releasing building “jQueryDeuce”? Take the best of what is in jQuery, do not abandon jQuery, continue to upgrade and improve jQuery, but redo the whole thing the way you would if you started from scratch and release it as a separate library?
Kyle (May 13, 2011 at 3:25 pm)
Why not just make the method backward compatible?
Tim Down (May 13, 2011 at 6:55 pm)
Andrew: Where is it written *exactly* what attr() is supposed to do? In particular in the case of custom attributes? A custom attribute is accessible via getAttribute() but not via a property in most browsers, while attr() (prior to 1.6) used an undocumented combination of properties and attributes, so it’s unclear what to expect.
Pies (May 14, 2011 at 2:30 am)
“people like having stability in their API and will cherish that over everything else”
Hear hear, one of the things I’ve learned from open source development scene was the resistance to change inherent in every successful project. It’s as natural and necessary, as it is limiting.
Mike Finney (May 14, 2011 at 3:04 pm)
You are all awesome! Thank you for your time and effort!
Richie (May 15, 2011 at 11:11 pm)
To echo Mike Finney, massive kudos to the time and effort put it by you and the team.
Raghibsuleman (May 16, 2011 at 3:52 am)
Thanks dear submitting good post here…
fashion jewelry online (May 16, 2011 at 10:52 pm)
THANK U FOR YOUR HARD WORKING. IT IS VERY NICE.
David Rivers (May 17, 2011 at 8:32 am)
Why would someone, upgrading from a 1.x version of a library to a 2.x version, expect anything less than at least a few major changes? This concern hasn’t stood in the way of, e.g. Rails developers, with Rails 3 containing numerous breaking changes for the sake of a better library.
Der Kieler (May 17, 2011 at 12:51 pm)
Thanx a lot for this helpful article …!
Joe Dempsey, Sr. (May 18, 2011 at 7:53 am)
My initial reaction is that you shouldn’t pander to all the lazy users, no matter how many or how vocal. The “purity” of he solution should be paramount. It now seems that there are a lot of people out there who would agree with me. I think 1.6.1 was a small step backwards. You can’t (and shouldn’t) please all (or most) of the people all (or most) of the time.
John Isaacks (May 18, 2011 at 11:36 am)
So instead of created jQuery 2.0 with a major API change, any chances you might just create a entirely new JS Library to succeed jQuery?
BlueRaja (May 18, 2011 at 6:15 pm)
Just as long as you don’t take the Microsoft standpoint that “stability in API” means “don’t ever fix any bugs in the API” :)
Powerserve (May 18, 2011 at 9:54 pm)
I was looking for something like prop() the other day. It will certainly be helpful, thanks!
Where would one go to participate in the weekly meetings?
sawebdesigns (May 18, 2011 at 10:18 pm)
Why not backward compatible??
Ben Hayes (May 19, 2011 at 12:55 am)
Clearly there’s a balancing act to do here. But don’t compromise the future elegance and efficiency of JQuery for the sake of not upsetting a few people in the short term.
And don’t forget the success of OSX following OS9!
Stephen Tudor (May 19, 2011 at 5:54 am)
I personally feel that “caveat emptor” is the correct approach when upgrading any piece of OSS. At least read the release notes, people. For 1.6, right at the top, was a section called “Breaking Changes.” How could that have been more clear?
In fairness, it may be better practice to deprecate features several releases prior to their change/removal. Either way, I’m incredibly thankful and indebted to the jQuery team for all their hard work and dedication to the project. jQuery continues to be a killer library because of you folks!
Ian Atkins (May 21, 2011 at 2:54 am)
I’d say push forward, old versions can still be used for older code.
If someone is implementing the newer version of jQuery it should be expected that there would be some glitches and changes.
I personally don’t update jQuery to the latest version on every production site, I only do that when doing maintenance or updating the code. In those situations I’d not expect everything to work straight off.
A pre-release notification email would be useful though!
Marat (May 23, 2011 at 2:05 am)
What about dataset data-* attributes?
Nathan (May 25, 2011 at 3:07 am)
“we only do major changes in the 1.x major releases of jQuery”
Surely that means that people shouldn’t upgrade to a 1.x major release without checking it first.
jfbcb (May 25, 2011 at 10:20 pm)
1.6 ? it’s too fast …we just use 1.4.4 now in our project..well,big fan from china.
gewgwegwe (May 26, 2011 at 9:57 pm)
why not release “jQuery 2” under a different name? If people like it they will use it; and it will not affect old jQuery users.