Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JQuery event model and preventing duplicate handlers

Once again I want to load a page which contains its own script into a div using $("divid").load(...). The problem I face is related to events. Let's say we trigger("monkey") from the parent page and on the loaded page we bind("monkey") and just do an alert("monkey bound"). If the same load method is called multiple times, the bind is called multiple times. Now I could just unbind it before I bind it, or check the number of handlers before the bind and then not bind it to prevent this. Neither option is scalable as what if I later want to bind to that trigger in another "sub page" (a page loaded into a div).

What I ideally want to do then is check if the handler I am about to add already exists, but I still WANT to use anonymous handlers... (asking a bit much with that last request I think). Currently I have a workaround by using pre-defined/named methods and then checking this before the bind.

// Found this on StackOverflow function getFunctionName(fn) {  var rgx = /^function\s+([^\(\s]+)/  var matches = rgx.exec(fn.toString());  return matches ? matches[1] : "(anonymous)" }  function HandlerExists(triggerName, handlerName) {         exists = false;         if ($(document).data('events') !== undefined) {             var event = $(document).data('events')[triggerName];             if(event !== undefined)             {                 $.each(event, function(i, handler) {                     alert(handlerName);                     if (getFunctionName(handler) == handlerName) {                         exists = true;                     }                 });             }         }         return exists;     } 

This is a pretty crude way of going about it I feel, but appears to work. I just do the following before the bind as follows:

if (!HandlerExists("test", "theMethod")) {     $(document).bind("test", theMethod); } 

Does anyone have a more elegant solution? for instance, is there any way to check a particular script is loaded? so I could use getScript() to load the js from the child page on first load, and then simply not load it on subsequent loads (and just fire a trigger which would be handled by he preexisting js)..

like image 791
Mr AH Avatar asked Feb 01 '10 21:02

Mr AH


People also ask

Can we have more than one event handler method for same event?

One event can have more than one event handler method in the same class or in different classes. At the run time only one handler method will be triggered at a time. After triggering the one that has to be deactivated and then another handler method will have to be registered to be triggered.

What are events and event handlers in jQuery?

The $(document).ready() method allows us to execute a function when the document is fully loaded. This event is already explained in the jQuery Syntax chapter. The click() method attaches an event handler function to an HTML element. The function is executed when the user clicks on the HTML element.

What is difference between on and bind in jQuery?

on() method is the preferred method for attaching event handlers to a document. For earlier versions, the . bind() method is used for attaching an event handler directly to elements. Handlers are attached to the currently selected elements in the jQuery object, so those elements must exist at the point the call to .

What is an Eventhandler in JavaScript?

Event handlers are the JavaScript code that invokes a specific piece of code when a particular action happens on an HTML element. The event handler can either invoke the direct JavaScript code or a function.


1 Answers

Prevent duplicate binding using jQuery's event namespace

There are actually a couple different ways of preventing duplicate. One is just passing the original handler in the unbind, BUT if it is a copy and not in the same space in memory it will not unbind, the other popular way (using namespaces) is a more certain way of achieving this.

This is a common issue with events. So I'll explain a little on the jQuery events and using namespace to prevent duplicate bindings.



ANSWER: (Short and straight to the point)


// bind handler normally $('#myElement').bind('myEvent', myMainHandler);  // bind another using namespace $('#myElement').bind('myEvent.myNamespace', myUniqueHandler);  // unbind the unique and rebind the unique $('#myElement').unbind('myEvent.myNamespace').bind('myEvent.myNamespace', myUniqueHandler); $('#myElement').bind('myEvent.myNamespace', myUniqueHandler);  // trigger event $('#myElement').trigger('myEvent');  // output myMainHandler() // fires once! myUniqueHandler() // fires once! 



EXAMPLE OF ANSWER: (Full detailed explanation)


First let's create an example element to bind to. We will use a button with the id of #button. Then make 3 functions that can and will be used as the handlers to get bound to the event:

function exampleOne() we will bind with a click. function exampleTwo() we will bind to a namespace of the click. function exampleThree() we will bind to a namepsace of the click, but unbind and bind multiple times without ever removing the other binds which prevents duplicating binding while not removing any other of the bound methods.

Example Start: (Create element to bind to and some methods to be our handlers)

<button id="button">click me!</button>   // create the example methods for our handlers function exampleOne(){ alert('One fired!'); } function exampleTwo(){ alert('Two fired!'); } function exampleThree(){ alert('Three fired!'); } 

Bind exampleOne to click:

$('#button').bind('click', exampleOne); // bind example one to "click"  

Now if user clicks the button or call $('#button').trigger('click') you will get the alert "One Fired!";

Bind exampleTwo to a namespace of click: "name is arbitrary, we will use myNamespace2"

$('#button').bind('click.myNamespace2', exampleTwo); 

The cool thing about this is, we can trigger the "click" which will fire exampleOne() AND exampleTwo(), or we can trigger "click.myNamespace2" which will only fire exampleTwo()

Bind exampleThree to a namespace of click: "again, name is arbitrary as long as it's different from exampleTwo's namespace, we will use myNamespace3"

$('#button').bind('click.myNamespace3', exampleThree); 

Now if 'click' get's triggered ALL three example methods will get fired, or we can target a specific namespace.

PUT IT ALL TOGETHER TO PREVENT DUPLICATE

If we were to continue to bind exampleThree() like so:

$('#button').bind('click.myNamespace3', exampleThree);  $('#button').bind('click.myNamespace3', exampleThree); $('#button').bind('click.myNamespace3', exampleThree); 

They would get fired three times because each time you call bind you add it to the event array. So, really simple. Just unbind for that namespace prior to binding, like so:

$('#button').unbind('click.myNamespace3').bind('click.myNamespace3', exampleThree);  $('#button').bind('click.myNamespace3', exampleThree); $('#button').unbind('click.myNamespace3').bind('click.myNamespace3', exampleThree);  $('#button').bind('click.myNamespace3', exampleThree); $('#button').unbind('click.myNamespace3').bind('click.myNamespace3', exampleThree);  $('#button').bind('click.myNamespace3', exampleThree); 

If the click function is triggered, exampleOne(), exampleTwo(), and exampleThree() only get fired once.

To wrap it all together in a simple function:

var myClickBinding = function(jqEle, handler, namespace){     if(namespace == undefined){         jqEle.bind('click', handler);     }else{         jqEle.unbind('click.'+namespace).bind('click.'+namespace, handler);     } }    

Summary:

jQuery event namespaces allow for binding to main event but also allow child namespaces to be created and cleared without effecting sibling namespaces or parent ones which with very minimal creative thinking allows prevention of duplicate bindings.

For further explanation: http://api.jquery.com/event.namespace/

like image 200
eli geske Avatar answered Sep 25 '22 17:09

eli geske