When you're working with plugins, or trying to be as unobtrusive as possible while doing a bunch of different things to your original markup, sometimes you have the problem of specific elements being triggered by multiple actions.

What happens when one action ends up replacing (visually) or covering up one element with another? Typically it's not a problem - unless the element that was replaced or covered up had an event attached to it. I had this happen to me recently when one jQuery script (dynamic icon overlay using a span) covered up another script (onclick event for an image to load a modal window for a video player). Uh oh!

I could have ignored the problem and simply duplicated the original images and added the "play" icon directly to the images themselves. However, if I ever should want to change the icon, that would require modifying all of the images again - and I'd need to keep the original images somewhere if that were ever the case. I could have built the overlay in to the original script, but then it's sort of losing scope on its original focus and intention.

It seemed the best way to combat the problem was to try to get the event(s) (a click event in this case) that was registered on the IMG element, and apply it to the SPAN that was overlayed on top of it.

While searching for answers, I accidentally stumbled across slides from a talk by John Resig that contained a bit of jQuery that I had never known about before - but apparently every time I now hear about it, every one raves about it. It's jQuery's $.data() utility method. Through using this method (and outputting JSON data directly through an alert box using Firefox's proprietary toSource() function), I was able to ascertain information about the events associated with a specific element.

Note: The following alert would only work in Firefox. To alert JSON in all (native JSON unsupported) browsers, you'd want to use Douglas Crockford's JSON2. In newer browsers, you should be able to just use the stringify() function (I just chose not to).

The above JS code acting on the HTML element (in my code, anyway) created the following string:

At first I thought I could just copy the data from one element's data property to another element. Unfortunately that does not work as it doesn't actually register anything. I asked a question over at StackOverflow, and although the answers that I got weren't exactly what I was looking for, someone had already created a jQuery events copy plugin. I didn't want to have dependencies on other plugins in my code, so I looked over the plugin's code to go about my own solution.

Since not all handlers will be using a plugin (and therefore simply contain a function name), very few will have a namespace. I didn't bother with that in my code (but I may refactor later). Instead, I took the necessary information and simply looped the events registered with the element, and re-binded them using jQuery's own bind() method.

Keep in mind that this specific piece of code I was working on created an overlay (an element that surrounded and rested) atop the target element (thus the parent().bind). Your particular uses may vary. The 2nd bind() was also specific to this code's purpose. Although a SPAN tag was created, if the target element's parent was not an anchor element, it would create one and wrap itself in that. The only way to prevent the default behavior of an anchor tag was to issue a 2nd bind (I didn't know how to pass it in to the initial bind call).

Note: jQuery's "helper" events (ex: mouseenter, mouseleave) duplicate and/or enhance functionality of the mouseover and mouseout behaviors. Because of this, if you use jQuery to create a mouseenter event, internally it binds the element with a mouseover event, and then binds again with its own overriding event (from what I can tell, anyway). Therefore, my code here copies and registers both events (mouseenter and mouseover) and unfortunately will also fire both of them. This code (as-is) works best on native event types.

Unfortunately I was unable to determine how to unregister or remove specific events. After looping I could remove all events from an object, but I couldn't perceive a way to do it within the loop itself. If you had to target a specific handler in your loops, I don't know if it would be possible to move events, but only copy.


Trackback specific URI for this entry
    No Trackbacks


    #1 50r on 12/17/12 at 09:46 AM [Reply]
    I have a problem i want to have an element (button) when clicked for the first time, it fires an event and when clicked the second time it fires another event is that possible?

Add Comment

E-Mail addresses will not be displayed and will only be used for E-Mail notifications.

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.

BBCode format allowed