Writing Effective jQuery Code: Using $.data()

As you saw in the previous section, the new HTML5 data attribute is designed for structured, programmatic access to custom attributes. jQuery provides a straightforward method to do just that with $.data(). Any data attributes set on an HTML element are immediately available to be retrieved with $.data(). Though that’s extremely convenient, $.data() also provides the ability to bind any data to a DOM element. This allows arrays and complicated objects to be stored as well as the string values previously possible with hand-rolled custom attributes. It should be noted that while $.data() can read HTML5 data attributes, it doesn’t actually write values to elements in the form of data- attributes. This makes sense because arbitrary arrays and objects don’t lend themselves to being stored as string values of HTML attributes.

This is extremely powerful, and if you’ve been doing this for a while, it should feel like something you’ve been searching for your whole career.

If you’ve ever passed an object as an argument between several methods, you’ll be happy to know you’ll never have to do that again if you learn to embrace the $.data() method. Gone are the days of managing application state with function argument chains spreading across a half dozen method calls. Now, you can simply bind application or component data directly on the DOM element itself for convenient, direct access throughout the application life cycle.

Additionally, it’s important to note that the data API stores data in a way that’s safe from circular references, which prevents memory leaks.

A note on support: HTML5 data attribute support was added in jQuery 1.4.3 and a revision was released to match the W3C spec more closely in jQuery 1.6.

1. The Basics of the .data() API

Like many jQuery methods, $.data() can be used as both a setter and a getter. If two arguments, as a name/value pair, or an object of name/value pairs is passed in, $.data() will set the data values accordingly. A single string passed in will return the value of named data property. Some basic examples, including strings, Boolean, arrays, and objects being used as values for the $.data() method, are shown in Listing 10-14.

LISTING 10-14: Simple .data() examples

$(‘#dashboard’).data(‘updated’, 1321358806453);

$(‘body’).data(‘fantastic’, true);

$(‘#settings’).data(‘faves’, [1,4,6,8,9,14,27,42]);

$(‘#boston’).data(‘bostonTeams’, {

‘nba’ : ‘Celtics’, ‘nhl’ :  ‘Bruins’, ‘mlb’ :  ‘Red Sox’, ‘nfl’ :  ‘Patriots’ });

Code snippet is from data-examples.txt

Although the basics of the API are straightforward, the power and convenience can’t be understated. Having a coherent, standard method of storing and retrieving application data clears up years of awkward coding and disparate patterns. The following section lays out this benefit with a more realistic example.

Before we look at that example, it should be noted that though $.data() allows for storing page- level data, it does not help you at all with storing persistent data. To store persistent data, you’ll still have to deal with cookies or the new TML5 storage API, which are the standards for persistent data in the browser.

2. Fully Leveraging the Data API

Listing 10-15 illustrates an application fragment. This piece initializes a small Google Maps application. In it, you create a Google Map and use the W3C’s new Geolocation API to place a marker on the map based on the user’s latitude and longitude.

Throughout this example, the .data() method is used to capture variables, objects, and even instantiated Google Maps objects.

Initially, you store a reference to the map itself. Every Google Maps API call works off of an instantiated object; for example, a map, geocoder, or marker. Storing the reference to your map simplifies later map manipulations. You also store the initial mapOptions object. This is a simple scheme to store the initial state of the map if you need to reset it for any reason.

Later on, in both the success and failure functions, you store a geocoder object and an initialLocation. The geocoder can be used for any later address lookups without the cost of instantiation, and the initialLocation can be used to reset or recenter the map based on the updated latitude and longitude provided by the geolocation lookup.

LISTING 10-15: Using .data() in an application context

var loadMap = {

init : function() {

var GM = google.maps,

defaultPosition = new GM.LatLng(42, -71),

mapOptions = {

zoom: 12,

center: defaultPosition,

mapTypeId: GM.MapTypeId.ROADMAP

},

map = new GM.Map( document.getElementById( ‘map’ ), mapOptions);

$( “#map” ).data({ “map” : map, “mapOptions” : mapOptions } );

var success = function( data ){

var position = new GM.LatLng(

data.coords.latitude,

data.coords.longitude ),

niceAddress = “Your location”,

geocoder = new GM.Geocoder();

$( “#map” ).data( “geocoder” , geocoder );

geocoder.geocode(

{ ‘latLng’: position },

function( results, status ) {

if ( status == GM.GeocoderStatus.OK ) {

if (results[0]) {

niceAddress = results[0].formatted_address;

}

}

var infowindow = new GM.InfoWindow({

map: map,

position: position,

content: niceAddress

});

$( “#map ).data( “infowindow” , infowindow )

});

map.setCenter( position );

$( “#map” ).data( “initialLocation” , position )

},

failure = function( error ){

var formResponse = function(e){

var geocoder = new GM.Geocoder(),

position = defaultPosition,

niceAddress = “Sorry We Couldn’t Find Your Location”;

$( “#map” ).data( “geocoder” , geccocoder );

geocoder.geocode(

{ ’address’: $(”#location”).val() },

function( results, status ) {

if ( status == GM.GeocoderStatus.OK ) {

//set position

}

var options = {

map: map,

position: position,

content: niceAddress

},

infowindow = new google.maps.InfoWindow(options);

$( “#map” ).data( “infowindow” , infowindow )

map.setCenter( options.position );

$( “#map” ).data( “initialLocation” , position )

$( ”#geocode” ).hide();

}

)

return false;

}

var $fallback = $( ”<from id=’geocode’></form>” );

if ( error ) {

switch( error.code ) {

/* error handling */

}

}

fallback.append(”<label for=,location’>Enter Your Location”

+ “<input type=’text’ id=’location’ /></label>”

+ ”<input type=’submit’ />”);

fallback.bind(“submit”/formResponse);

$(”#main”).append( $fallback );

};

if (navigator.geolocation){

navigator.geolocation.getCurrentPosition(

success,

failure,

{timeout:5000});

} else {

failure();

}

},

reset : function(){

var map = $( “#map” ).data( “map” ),

position = $( “#map” )

.data( “initialLocation” ),

infowindow = $( “#map” )

.data( “infowindow” , infowindow );

infowindow.close()

map.setCenter( position );

}

}

$( document ).ready( loadMap.init );

Code snippet is from data-api.txt

In just this small example, you’ve stored a wealth of data about your application in an accessible, standard way. Accessing it in the simple reset method, you have immediate access to the current map, infowindow, and the original latitude and longitude coordinates supplied when the map was created, allowing you to quickly reset the map to its original state. Once you start to leverage the $data() method across an application, you’ll wonder how you ever survived without it.

Source: Otero Cesar, Rob Larsen (2012), Professional jQuery, John Wiley & Sons, Inc

Leave a Reply

Your email address will not be published. Required fields are marked *