In the beginning (well, beginning with jQuery 1.2.3 in early 2008) there was the
Most jQuery code sets data values using the higher-level
So to recap: At the inception of these APIs, they were only about getting and setting values associated with DOM elements in memory. Most importantly, the data was managed to ensure no memory would leak when the DOM elements were removed. Many internal jQuery features such as event handling and toggle state memory use these data APIs and their benefits.
It's not a perfect marriage, though. HTML5
Here are the rules of the road:
jQuery.data()
API. It offers a way to associate JavaScript data — strings, numbers, or any object — with a DOM element. As long as you manipulate the DOM element with jQuery, the library ensures that when the DOM element goes away, the associated data goes away as well. This is especially important for older versions of IE that tend to leak memory when JavaScript data is mixed with DOM data.Most jQuery code sets data values using the higher-level
.data()
API; for example, $("div").data("imaDiv", true)
sets a boolean value on every div
in the document. This API, in turn, calls down to jQuery.data()
with each element to set the value. For completeness, there are also jQuery.removeData()
and .removeData()
to remove data elements, and jQuery.hasData()
to determine if any data is currently set for an element.So to recap: At the inception of these APIs, they were only about getting and setting values associated with DOM elements in memory. Most importantly, the data was managed to ensure no memory would leak when the DOM elements were removed. Many internal jQuery features such as event handling and toggle state memory use these data APIs and their benefits.
Enter HTML5
A few years later, HTML5 became popular and associated another concept with the word "data" through itsdata-*
attributes and the associated DOM .dataset
property. This isn't quite the same as jQuery's original idea of data: It involves values being associated with HTML elements in markup and not DOM elements in memory. But they are logically close enough that we added the ability to read HTML5 data-*
attributes into jQuery's data object starting with version 1.4.It's not a perfect marriage, though. HTML5
data-*
attribute names are more like CSS names; a name like data-shrivel-up
is turned into shrivelUp
when read in JavaScript-land. No such rules ever applied to jQuery data names in the past, which means we may have to try both shrivel-up
and shrivelUp
to find a match. We know it's not ideal, but it's a consequence of trying to fit two concepts with differing semantics into a single API.Rules of the Road for Data APIs
With that history in mind, there are a few important things you should know in order to use the.data()
and jQuery.data()
APIs effectively. To give you a better sense of what's going on, the items are illustrated with some code. Assume that each code block runs independently of the others and that they all refer the following HTML:HTML:
- <div id="novel" data-novelist='{"firstname": "Jose", "lastname": "Saramago"}'>Blindness</div>
- <div id="poem" data-poet="Edna St. Vincent Millay">Sonnet 18</div>
- <div id="story" data-story-writer="Raymond Carver">A Small, Good Thing</div>
Here are the rules of the road:
-
Only the
The in-memory data object for an element is initialized from those.data()
API reads HTML5data-*
attributes, and it does so once.data-*
attributes the first time you call.data()
for the element. Any subsequent changes to the attributes are ignored, since jQuery has already cached the data.
Rule: If HTML5data-*
attributes change during program execution, use jQuery's.attr()
method to get the current values.
JavaScript:
- console.log( $.data( document.getElementById('poem'), 'poet' ) );
- //>> undefined
- console.log( $('#poem').data('poet') );
- //>> "Edna St. Vincent Millay"
- // Change the HTML5 data-poet attribute
- $('#poem').attr('data-poet', 'Edmund Spenser');
- console.log( $('#poem').data('poet') );
- //>> "Edna St. Vincent Millay"
-
The
That means sequences of digits or exponential-looking values like.data()
API converts HTML5data-*
values to Javascript types whenever possible."11E5"
are translated to a Javascript Number type, the string"true"
becomes Booleantrue
, and a valid JSON string becomes a JavaScript object.
Rule: To get HTML5data-*
attributes as strings without data conversion, use jQuery's.attr()
method.
JavaScript:
- console.log( $('#novel').data('novelist') );
- //>> Object> {"firstname": "Jose", "lastname": "Saramago"}
- console.log( $('#novel').attr('data-novelist') );
- //>> '{"firstname": "Jose", "lastname": "Saramago"}'
-
The lower-level
However, if thejQuery.data()
API does not read HTML5data-*
attributes..data()
API has been called already on that DOM element,jQuery.data()
will "see" the values that it has already read from thedata-*
attributes. Conversely, ifjQuery.data()
sets a value with the same name as an HTML5data-*
attribute and.data()
later reads them, the HTML5 attribute is ignored.
Rule: To prevent confusion, do not use similar names for HTML5data-*
attributes and strictly internal data stored usingjQuery.data()
or.data()
on the same elements.
JavaScript:
- // Before reading with .data()
- console.log( $.data( document.getElementById('poem'), 'poet' ) );
- //>> undefined
- console.log( $('#poem').data('poet') );
- //>> "Edna St. Vincent Millay"
- // After reading with .data()
- console.log( $.data( document.getElementById('poem'), 'poet' ) );
- //>> "Edna St. Vincent Millay"
-
No jQuery data API ever changes HTML5
Most uses ofdata-*
attributes..data()
and.removeData()
are still for the original purpose of associating data with DOM elements in memory. Updating DOM attributes each time data was changed would slow things down for no good reason. Also, it's not even possible to serialize all data types that might be attached to a DOM element, such as functions, references to other DOM elements, or custom JavaScript objects.
Rule: To update or remove HTML5data-*
attributes, use jQuery's.attr()
or.removeAttr()
methods.
JavaScript:
- console.log( $('#poem').data('poet') );
- //>> "Edna St. Vincent Millay"
- console.log( $('#poem').attr('data-poet') );
- //>> "Edna St. Vincent Millay"
- // Change the HTML5 data-* attribute
- $('#poem').attr('data-poet', 'William Shakespeare');
- console.log( $('#poem').data('poet') );
- //>> "Edna St. Vincent Millay"
- console.log( $('#poem').attr('data-poet') );
- //>> "William Shakespeare"
- // Change .data('poet')
- $('#poem').data('poet', 'Edmund Spenser');
- console.log( $('#poem').data('poet') );
- //>> "Edmund Spenser"
- console.log( $('#poem').attr('data-poet') );
- //>> "William Shakespeare"
-
All
So,data-*
names are stored in camelCase in the jQuery data object, using W3C rules.data-caMEL-case
becomes thecamelCase
property in the data object and should be accessed using.data("camelCase")
. Because many people will use.data("camel-case")
instead, we convert that tocamelCase
as well, but only if no data item namedcamel-case
is found so it's faster to use the first form. If you get the entire data object using code likedata = jQuery.data(elem)
, you must usedata.camelCase
to access the data item.
Rule: When accessing data taken fromdata-*
attributes, and especially when accessing the data object directly, use the W3C camelCasing conventions.
JavaScript:
- // Not recommended:
- console.log( $('#story').data('STORY-writer') );
- //>> "Raymond Carver"
- // Better:
- console.log( $('#story').data('storyWriter') );
- //>> "Raymond Carver"
- // Broken:
- console.log( $('#story').attr('dataStoryWriter') );
- //>> undefined
- // Better:
- console.log( $('#story').attr('data-STORY-writer') );
- //>> "Raymond Carver"
Pick What You Like
Over time, jQuery's.data()
API has taken on more responsibilities than it originally had when it was just a way to associate in-memory data with DOM elements and prevent IE leakage. If you need only a simple way to read HTML5 data-*
attributes as strings, then the .attr()
method may be the best choice, even though the siren-song-name .data()
may be telling you otherwise. Whether you use .attr()
or .data()
, they work consistently across browsers all the way back to IE6 — even if the browser doesn't support HTML5 — so just choose the API with the feature set that works best for your needs.jQuery.map() in 1.6
Among all of the great fixes and additions to jQuery 1.6, I'm happy to say that jQuery.map() now supports objects! The previous map only supported arrays. With other libraries already offering object support for map, it was a nice addition.
Merging jQuery Deferreds and .animate()
Editor's Note: This article originally appeared on danheberden.com.
jQuery’s
But what happens when you want to bridge the gap between ajax requests and animating? When you want to queue a bunch of animations, get data from the server, and handle it all at once, without a crap-load of nested callbacks? That’s when
jQuery’s
.animate()
method, and the shorthand methods that use it, are fantastic tools to create animations. Creating animations that link together to achieve a particular effect, and do something specific at the end of the animation, can be a painful, messy task. Luckily, we have .queue()
for mashing animations together.But what happens when you want to bridge the gap between ajax requests and animating? When you want to queue a bunch of animations, get data from the server, and handle it all at once, without a crap-load of nested callbacks? That’s when
jQuery.Deferred()
puts on its cape, tightens its utility belt, and saves the day.Introducing jQuery API Search
Half-baked tutorials and plugins have been stacking up for months in my virtual kitchen, waiting for me to fire up the oven, finish the cooking, and spread them out on the table. For some reason, though, I've become less and less sure about whether I've put all the right ingredients into the mix. It's irritating, to be sure, but I'm tired of fretting about it. I'm going to consider this the first of what I hope to be many "taste tests" — experiments in various degrees of completion thrown against the wall to see what, if anything, sticks.
As some of you may know, the online jQuery documentation went through a major overhaul in January of this year, coinciding with the release of jQuery 1.4. Packt Publishing "open sourced" the jQuery 1.4 Reference Guide that Jonathan Chaffer and I had been writing, allowing us to put its entire contents (and more) on api.jquery.com. Some of you may also know that the raw XML content of the site is available as a single file, which has allowed other sites such as jqapi.com and idocs.brandonaaron.net to provide alternative views of that content. But what most of you probably do not know is that the jQuery API has been available for quite some time as a searchable API that returns the results in JSON format.
As some of you may know, the online jQuery documentation went through a major overhaul in January of this year, coinciding with the release of jQuery 1.4. Packt Publishing "open sourced" the jQuery 1.4 Reference Guide that Jonathan Chaffer and I had been writing, allowing us to put its entire contents (and more) on api.jquery.com. Some of you may also know that the raw XML content of the site is available as a single file, which has allowed other sites such as jqapi.com and idocs.brandonaaron.net to provide alternative views of that content. But what most of you probably do not know is that the jQuery API has been available for quite some time as a searchable API that returns the results in JSON format.
Great Ways to Learn jQuery
These jQuery resources will set you on the path towards mastering jQuery.
Written Articles
- Getting Started with jQuery - this is the official jQuery getting started guide.
- jQuery for JavaScript Programmers - Simon Willison (creator of django) gives you an introduction to jQuery for people who already understand JavaScript.
- jQuery Crash Course - Nathan Smith gives a quick introduction to jQuery on Digital Web Magazine.
- Introduction to jQuery - Rick Strahl, well-known for his work developing with Microsoft technologies, gives his introduction to jQuery with part two covering using jQuery with ASP.NET.
E-Books
- jQuery Fundamentals - open-source e-book written by Rebecca Murphey in collaboration with other well-known members of the jQuery community.
- jQuery Enlightenment - Cody Lindley's e-book covers advanced topics on jQuery with links to working code examples in jsbin.
Autocomplete Migration Guide
The jQuery Autocomplete plugin got a successor recently, the jQuery UI Autocomplete. In this guide we'll look at the old plugin API step-by-step, and how to migrate to the new API.
At first it may look like the new plugin supports barely any of the old options. We'll see how all the old options can be implemented using the three new options and the six events.
The old plugin had two arguments: data or url, and options. Lets start with that data-or-url argument. With the new autocomplete plugin, you'll just pass the data or url to the
So, with the old plugin you'd have this code:
And that becomes, easy enough:
The same applies if you provided a URL as the first argument, although there is a difference between the two plugins for remote data. The old plugin expected a special format with pipes to separate values and newlines to separate rows. That is gone for good, the Autocomplete widget now works with JSON by default. The simplest form is the same as in the example above, an array of string values.
Instead of an array of strings, the widget also accepts an array of objects, with at least a label or value property, or both, in addition to whatever else you need. More on that can be found in the documentation and various demos, eg. the Custom Data demo shows how to use custom properties and even display them.
Lets look through the rest of the options for the old plugin, and what to do with them for the new plugin:
At first it may look like the new plugin supports barely any of the old options. We'll see how all the old options can be implemented using the three new options and the six events.
The old plugin had two arguments: data or url, and options. Lets start with that data-or-url argument. With the new autocomplete plugin, you'll just pass the data or url to the
source
option.So, with the old plugin you'd have this code:
JavaScript:
- $("input").autocomplete(["a", "b", "c"]);
And that becomes, easy enough:
JavaScript:
- $("input").autocomplete({
- source: ["a", "b", "c"]
- });
The same applies if you provided a URL as the first argument, although there is a difference between the two plugins for remote data. The old plugin expected a special format with pipes to separate values and newlines to separate rows. That is gone for good, the Autocomplete widget now works with JSON by default. The simplest form is the same as in the example above, an array of string values.
Instead of an array of strings, the widget also accepts an array of objects, with at least a label or value property, or both, in addition to whatever else you need. More on that can be found in the documentation and various demos, eg. the Custom Data demo shows how to use custom properties and even display them.
Lets look through the rest of the options for the old plugin, and what to do with them for the new plugin:
- autoFill: Gone with no immediate replacement available, for good reasons: The default behaviour when selecting items via keyboard now puts the focussed value into the input, like the Firefox Awesomebar does it. It's not the same as what the autoFill option did, but there should be no need to recreate that effect.
- cacheLength: There is no built-in caching support anymore, but it's really easy to implement your own, as shown by the Remote with caching demo.
- delay: Still exists with the same behaviour, but the default is always 300 milliseconds.
- extraParams: Extra params and all other Ajax related options can be customized by using a callback for the
source
option. Use$.ajax
to send the actual request, with theresponse
callback argument passed tosource
as thesuccess
callback for the$.ajax
call. The Remote JSONP datasource demo has an example for that. - formatItem, formatMatch, formatResult, highlight: All gone, instead use the
source
option to either provide the formatted data from your serverside, or implement a custom source to do special formatting. The combobox demo shows how to do that, with a more extensive explanation of that demo right on this site. - matchCase, matchContains, matchSubset: All gone, too. The builtin matcher for local data will do a case-insensitive match-contains, everything else has to be implemented on the serverside or using the source option. The combobox linked just above also has an example for that.
- max: Gone; if your server sends too many items, pass a function for the
source
option that calls$.ajax
and truncates or filters the resulting list. - minChars: Still present, but was renamed to
minLength
. Behaves just the same, even the default is still the same, withminLength: 1
. - multiple, multipleSeperator: Not built-in anymore, but easy to recreate. There are two demos for this, once with local data, once with remote data.
- mustMatch: Gone, but easy to implement with the
select
event. Once more, the combobox provides an example for that. - scroll, scrollHeight: These option are gone, but the underlying Menu widget actually has support for scrolling. If you have enough items and specify a height via CSS, the menu will scroll.
- selectFirst: Similar to autoFill (at the top of this list), this option is gone and has now immediate replacement, nor a need for one. The behaviour for selecting values is solid enough to make this option redundant.
- width: Gone and not required anymore. The menu will automatically be as wide as the input it completes, or wider, as the content requires. And you can always restrict with width using CSS.
0 comments:
Post a Comment