.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
, se
lectedIndex
, or defaultValue
) 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. Posted: May 13th, 2011
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!
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()
with prop()
calls.
~Neal
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!
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
Nice post John!
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.
Couldn’t you make a new attribute only function and depreciate the old one? Something like ‘.attb’ to go along with ‘.prop’
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.
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.
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.
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.
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?
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?
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.
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.
I take that back: you can use “for” as a property name, just not as an identifier.
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.
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 for blerg
.
Here’s a thought, issue deprecation warnings on an API _before_ it changes.
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?
Why not just make the method backward compatible?
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.
“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.
You are all awesome! Thank you for your time and effort!
To echo Mike Finney, massive kudos to the time and effort put it by you and the team.
Thanks dear submitting good post here…
THANK U FOR YOUR HARD WORKING. IT IS VERY NICE.
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.
Thanx a lot for this helpful article …!
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.
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?
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” :)
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?
Why not backward compatible??
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!
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!
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!
What about dataset data-* attributes?
“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.
1.6 ? it’s too fast …we just use 1.4.4 now in our project..well,big fan from china.
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.
Travis (May 13, 2011 at 9:12 am)