Tuesday, January 31, 2012

How to Access jQuery's Internal Data

As you may or may not be aware as of jQuery 1.7 the whole event system was rewritten from the ground up. The codebase is much faster and with the new .on() method there is a lot of uniformity to wiring up event handlers.

One used to be able to access the internal events data and investiate what events are registered on any given element, but recently this internal information has been hidden based on the following ticket...

"Ticket #8921: jQuery Private Data Should Stay Private

It seems that the "private" data is ALWAYS stored on the .data(jQuery.expando) - For "objects" where the deletion of the object should also delete its caches this makes some sense.

In the realm of nodes however, I think we should store these "private" members in a separate (private) cache so that they don't pollute the object returned by $.fn.data()"

--http://bugs.jquery.com/ticket/8921

Although I agree with the above change to hide the internal data, I have found having access to this information can be helpful for debugging and unit testing.


Thankfully, if you still need access to the internal data it is still accessible, however, you need to use a method that isn't officially documented... which means that you should be cautious about using it. I would encourage you to not use the undocumented ._data() method in production code.


You can view, run, and edit the above code sample from JSBin.

On the plus side, if you access the old .data() method with "events" as a parameter that will retrieve the internal data containing events and event handlers.

As a side note, if you are looking for events attached using the .live() or .delegate() methods then you will need to look at either the document element or whatever element you delegated against.

Update: Rick Waldron informed me on twitter that the jQuery Core team plans on creating a supported plugin to access the internal data that jQuery maintains. This would be a much better solution than using the above undocumented ._data() method because undocumented methods are also unsupported methods ;) I only use the ._data() method for debugging or testing. You should try to avoid using it in any of your production code for this reason.

Monday, January 30, 2012

Find the jQuery Bug #3: Give Me Truth

Introduction


In this open-ended series I'll be showcasing a snippet of buggy jQuery code that you might encounter, explain what the problem is, and then identify how you can easily resolve the issue.

You can view other posts in this series...

The Desired Feature


We want to take the following HTML div and build a simple popover module that uses the jQuery UI Dialog widget.


The Buggy Code


The intent of the following code snippet is to verify that the div being used in the modal dialog exists in the DOM and that it has not been already initialized. We have an init method that should initialize the widget and then an open method that should launch the dialog. The code snippet has some problems. Do you see them?


You can view, run, and edit the above code sample from JSBin.

When we run the code, things seem pretty much like what we expected. The widget seems to have been initialized and then opens as expected. We don't actually see the error visually, but there is a problem hidden in the init() code. If you debug through the code you'll notice something odd when calling init() again. We put in checks to verify for the existence of the DOM element and that it hasn't been initialized yet, right? Well, that is where the problem lies. Do you see the problem now?

The Underlying Problem


At the root of the problem is how we are testing for truth! Both the ways we are checking for existence and initial state are flawed.

"jQuery( selector [, context] ) Returns: jQuery
Description: Accepts a string containing a CSS selector which is then used to match a set of elements." --http://api.jquery.com/jquery

The check for existence is incorrect, because just checking the result of $( "dialog-modal" ) doesn't get you anywhere. Where does it get you? It always evaluates as true because a call to $( selector ) returns the jQuery object and based on our truthy/falsey rules an object is always truthy! What does this mean? Well, it means the code to initialize the DOM element would execute even if it didn't exist at all!

".not( selector ) Returns: jQuery
Description: Remove elements from the set of matched elements." --http://api.jquery.com/not

In a similar fashion the check we were making for the initial state of the DOM element is incorrect. The intent was to check if the element did not have a particular class (.ui-dialog-content), which is added by jQuery UI when it initializes the dialog widget. If we take a look at the documentation for the .not() method we'll see that it too returns the jQuery object! The purpose of the method is to filter down the matches by removing elements that match the selector provided. So, we run into the same problem as above where we are always evaluating as truthy!

A Solution


The solution to fix these problems are really simple and straightforward. All you really need to do is to check how many items where matched by a jQuery selection and to use the .is() method instead of the .not() method.


You can view, run, and edit the above code sample from JSBin.

If you run the above code again you'll notice that the console.log message only shows up the first time the .init() method is called.

Conclusion


The key concept to remember here is to realize that testing against the jQuery object will always evaluate as true. As shown above it is easy to adjust your code accordingly.

There are other more advanced techniques that can be used for initialization as well. I'd encourage you to look into Doug Neiner's (@dougneiner) Contextual jQuery series (Part 1 and Part 2) that he gave at the jQuery Boston 2010 and 2011 Conferences. In particular he gave some really interesting just-in-time initialization techniques in the 2nd talk. I highly encourage you viewing these if you haven't already.

Until next time...

Friday, January 27, 2012

Having Fun with JavaScript and Skype Emoticons

I was chatting with Jim Cowart (@ifandelse) on Skype today about jQuery. He pasted in a snippet of code and Skype translated part of it into one of it's emoticons. He almost immediately updated the chat message to fix the issue, but it got me starting to think... and that can be very dangerous.

I thought to myself that it would be fun to create a program that intentionally utilize Skype emoticons. The following screenshot is the result of the program I put together. It is a restaurant where you can listen, eat, and drink ;)


As you can tell, it is a silly little program. The code for the above screenshot can be found below. Some of the icons I used are secret emoticons that you can lookup.


If you'd like to come up with your own Skype-enabled JavaScript program, then I'd like to see it. Share it in the comments. Have fun!