Calling jQuery's Data() Method Without Arguments

Posted February 1, 2010 at 10:10 AM

Tags: Javascript / DHTML

With jQuery 1.4, I was very happy to see that they finally gave us the ability to invoke the data() method without arguments. Calling the data() method in this way returns an object containing all of the keys stored using the data() method on this object. When I was working on my jQuery image zoom experiment, I made heavy use of this feature to store data points without having to call the data() method each end every time. I was able to do this because the object returned by the data() method is the actual data cache object - passed by reference - and not a copy of it. As such, once you have the data cache, direct changes to it will be reflected in all subsequent calls to the data() method on that object.

 
 
 
 
 
 
 
 
 
 

Of course, it never is quite that straightforward. jQuery's data() method only returns the object's data cache if the cache exists; and, the cache only exists if a value is currently being stored in it. If no keys have been stored in the cache, or all the keys have been deleted (using removeData()), then the data() method will return null, not an empty cache object. I assume that they are doing this for optimization purposes, but there's something I don't like about it; it makes the data() method's behavior dependent on the previous uses of data() and this difference in data() potential just seems dangerous.

To make the data() method's behavior uniform, we can override the original data() method to apply some intercepting business logic. In the following demo, you'll see that I wrap the original data method using my own data method (is that AOP - Aspect Oriented Programming??). My version of the data method then applies the call to the original data method and, if the data method returns a null cache object, I store a data point in the elements data cache before returning the data cache. While this definitely feels sloppy in and of itself, storing this bunk name/value pair forces the data cache to become sticky.

  • <!DOCTYPE HTML>
  • <html>
  • <head>
  • <title>Calling jQuery's Data() Method Without Arguments</title>
  • <script type="text/javascript" src="jquery-1.4.js"></script>
  • <script type="text/javascript">
  •  
  • // Here, we want to override the data() method so that
  • // non-argument calls to it will always return the data
  • // store object.
  • (function( $ ){
  •  
  • // Get a reference to the original data method.
  • var originalData = jQuery.fn.data;
  •  
  • // Override the data method to ensure that the data
  • // store is always returned.
  • jQuery.fn.data = function(){
  •  
  • // Check to see if there are any arguments passed
  • // in. This is the only case we care about.
  • if (!arguments.length){
  •  
  • // Get the storage object.
  • var dataStore = originalData.apply( this );
  •  
  • // Check to see if the dataStore exists. If
  • // it does, then just return it; otherwise,
  • // we'll have to create one.
  • if (dataStore){
  •  
  • // Return current store.
  • return( dataStore );
  •  
  • }
  •  
  • // If we made it this far, then the data store
  • // returned was null which means it has never
  • // be accessed before. To create it, we
  • // actually have to set a key in it. We also
  • // have to keep the key in there, otherwise
  • // jQuery will try to delete the data store.
  • originalData.apply( this, [ "_", "_" ] );
  •  
  • // Now that the dataStore object has been set
  • // as the hash, return it.
  • return( originalData.apply( this ) );
  •  
  • } else {
  •  
  • // No special case, simply pass method call
  • // to original method and return the result.
  • return(
  • originalData.apply( this, arguments )
  • );
  •  
  • }
  •  
  • };
  •  
  • })( jQuery );
  •  
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • // When the DOM is ready, init the scripts.
  • jQuery(function( $ ){
  •  
  • // Get a reference to the P tag.
  • var para = $( "p:first" );
  •  
  • // Get a reference to the data storage struct.
  • // When you call the data() method without any
  • // arguments, jQuery returns the actual storage
  • // object, not a duplicate of it.
  • dataStore = para.data();
  •  
  • // Now that we have the data storage object, we
  • // can update the values in it directly.
  • dataStore.name = "Tricia";
  • dataStore.isSexy = true;
  •  
  • // Now that we have updated the store object, let's
  • // update the text of the paragraph by re-referencing
  • // the data storage mechanism.
  • //
  • // NOTE: We did NOT have to re-store the data object
  • // in order to make these values available.
  • para.text(
  • para.data( "name" ) +
  • " is " +
  • (para.data( "isSexy" ) ? "" : " not " ) +
  • "sexy!"
  • );
  •  
  • });
  •  
  • </script>
  • </head>
  • <body>
  •  
  • <h1>
  • Calling jQuery's Data() Method Without Arguments
  • </h1>
  •  
  • <p>
  • <!-- Will be populated dynamically. -->
  • </p>
  •  
  • </body>
  • </html>

As you can see, the first part of this script overrides jQuery's native data() method to intercept and manipulate calls to the data() method made without any arguments. If the data() method returns null, I store the key, "_", in the element's data cache before re-querying the data() method to return a valid data cache object reference. In doing so, the rest of the demo can successfully retreive the data cache using the data() object regardless of the current state of the cache. In doing so, I am able to directly mutate the data cache without making unnecessary calls to the data() method. And, since this data cache is returned by reference, my data alterations are reflected in subsequent calls to the data() method.

When we run the above code, we get the following paragraph output:

Tricia is sexy!

As you can see, the direct data manipulation we performed on the data store object was successfully reflected in later calls to the data() method.

jQuery 1.4 finally gave us the ability to directly access the data cache being used by the data() method. The behavior of this method, however, depends tightly on the current state of the cache. To me, this difference in data() behavior feels unnecessary; and, while the above solution is not perfect by any means, I like that it simplifies the way in which the data() method can be used.




Reader Comments

Feb 1, 2010 at 11:02 AM // reply »
2 Comments

Hi Ben,

Suggest some good tutors/books to learn this JQuery framework.

Thanks!


Feb 1, 2010 at 11:19 AM // reply »
8,777 Comments

@Dave,

I think the fastest, low-level intro to the language would probably be Cody Lindley's jQuery Enlightenment book:

http://www.bennadel.com/blog/1713-jQuery-Enlightenment-By-Cody-Lindley.htm

Once you are comfortable with that, there are a number of other great jQuery books that I have reviewed on this site:

http://www.bennadel.com/blog/tags/12-Books-blog-entries.htm

Try looking at jQuery Cookbook, jQuery in Action, Learning jQuery, and the jQuery UI books. These are all great books and go into more depth.


Feb 1, 2010 at 12:06 PM // reply »
2 Comments

Thanks Ben!.. Will give them a try!.


Feb 2, 2010 at 12:34 PM // reply »
1 Comments

Is this new in 1.4?


Feb 2, 2010 at 12:43 PM // reply »
8,777 Comments

@Peter,

Calling data() without arguments... but not the data() method itself.


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Formatting: <strong>bold</strong> <em>italic<em>







  • Help Wanted - Find Your Next ColdFusion Job
Recent Blog Comments
Sep 3, 2010 at 5:48 AM
Scope Behavior When Using CFThread Inside Of ColdFusion Components
Thanks Ben, Excellent article and very precise explanation. Cheers Philip A question on invoking asynchronous save or some task and returning response back to the calling page. Using cfThread is ... read »
Sep 3, 2010 at 3:04 AM
Long Polling Experiment With jQuery And ColdFusion
@Ben, Thank you for your answer. If you are interested in - I solved the problem. It was, as you said, a buffer issue. Now when I'm getting a new request, the first thing I do is I'm sending some fa ... read »
Sep 3, 2010 at 1:29 AM
Using jQuery's SlideUp() and SlideDown() Methods With Bottom-Positioned Elements
Hey Ben, Thanks for clearing this up! Also, is there a way for the container to be open when you first load the page, so that when u click on the link it will slideUp? ... read »
Sep 3, 2010 at 12:29 AM
Bidirectional Data Exchange With ColdFusion's CFThread Tag
Thanks for posting this example, Ben. I plan to put something like this to use. I want to spawn up a thread to insert several records (possibly 1000s) into a database incrementing a counter upon ea ... read »
Sep 2, 2010 at 11:23 PM
Experimenting With HTML5's Cache Manifest For Offline Web Applications
Hi Ben, having checked all articles on Html5's appCache, is there a solution to just update newer files, using the manifest file? I am looking into using application cache to actually have an offline ... read »
Sep 2, 2010 at 3:11 PM
Long Polling Experiment With jQuery And ColdFusion
@Alex, It looks like some of the browsers implement some sort of buffering on the data request. I was definitely finding different behavior across browsers. I want to come back and figure this code ... read »
Sep 2, 2010 at 3:09 PM
Creating Base64-Encoded Data URLs For Images In ColdFusion
@Randall, At the very least, I think Chrome won't be able to close windows unless it opens them up, right? I am not sure. ... read »
Sep 2, 2010 at 2:17 PM
ColdFusion NumberFormat() Exploration
Ben - I have same question as Jim and I think maybe you misread it? I want numbers with non-zero decimal places to display the decimal, but those that have no decimal to display w/o the decimal poin ... read »