2

I'm usually preventing multiple binds to an element like this:

$(document)
    .find('.ui-input-search input')
    .filter(function() { return $(this).jqmData('bound') !== true; })
    .jqmData('bound', true)
    .on('change keyup', function (e) {
        //do sth
    });

Which works nicely when the element is on the page and "ready to use".

Problem is, I want to do the same with elements, that are dynamically added to a page. On these elements, JQM will not be done enhancing elements in some cases so binding to the elements being created sometimes does not work.

Question:
If I don't want to unbind on pagehide, how would I have to change the above code to also lock elements once the binding is set?

So I want to do something like this:

$(document).on('change keyup','.ui-input-search input', function (e) {
  // bind to the selector only once
});

but I can't use the :not selector .ui-input-search input:not(.bound) because of IE, so I'm curious:

Thanks for feedback!

frequent
  • 27,643
  • 59
  • 181
  • 333

3 Answers3

1

but I can't use the :not selector .ui-input-search input:not(.bound) because of IE, so I'm curious:

Quoting the browser support page:

Regardless of a browser's support of CSS selectors, all selectors listed at api.jquery.com/category/selectors/ will return the correct set of elements when passed as an argument of the jQuery function.

You can use the :not selector when forming a collection with jQuery, regardless of whether the browser's CSS engine supports the selector.

Asad Saeeduddin
  • 46,193
  • 6
  • 90
  • 139
1

There are several methods, you can find them in my other ARTICLE, or find them HERE. Just search for the chapter: Prevent multiple event triggering.

Prevent multiple event triggering

Because of interesting jQM loading architecture, multiple event triggering is a constant problem. For example, take a look at this code snipet:

$('#index').live('pagebeforeshow',function(e,data){    
    $('#test-button').live('click', function(e) {
        alert('Button click');
    });    
});

Or you can test it here: http://jsfiddle.net/Gajotres/yWTG2/

Each time you visit page #index click event will is going to be bound to button #test-button. There are few ways to prevent this problem:

Solution 1:

Remove event before you bind it:

$('#index').live('pagebeforeshow',function(e,data){    
    $('#test-button').die().live('click', function(e) {
        alert('Button click');
    });    
});

In case you have different events bound to an object:

$('#index').live('pagebeforeshow',function(e,data){    
    $('#test-button').die('click').live('click', function(e) {
        alert('Button click');
    });    
});

Solution 2:

Use a jQuery Filter selector, like this:

$('#carousel div:Event(!click)').each(function(){
    //If click is not bind to #carousel div do something
});

Because event filter is not a part of official jQuery framework it can be found here: http://www.codenothing.com/archives/2009/event-filter/

In a nutshell, if speed is your main concern then Solution 2 is much better then Solution 1.

Solution 3:

A new one, probably an easiest of them all.

$(document).on('pagebeforeshow', '#page', function(event){  
    if(event.handled !== true) // This will prevent event triggering more then once
    {
        // Some code
        event.handled = true;
    }
    return false;                
});

Tnx to sholsinger for this solution: http://sholsinger.com/archive/2011/08/prevent-jquery-live-handlers-from-firing-multiple-times/

pageChange event quirks - triggering twice

Sometimes pagechange event can trigger twice and it does not have anything to do with the problem mentioned before.

The reason the pagebeforechange event occurs twice is due to the recursive call in changePage when toPage is not a jQuery enhanced DOM object. This recursion is dangerous, as the developer is allowed to change the toPage within the event. If the developer consistently sets toPage to a string, within the pagebeforechange event handler, regardless of whether or not it was an object an infinite recursive loop will result. The pageload event passes the new page as the page property of the data object (This should be added to the documentation, it's not listed currently). The pageload event could therefore be used to access the loaded page.

In few words this is happening because you are sending additional parameters through pageChange.

Example:

<a data-role="button" data-icon="arrow-r" data-iconpos="right" href="#care-plan-view?id=9e273f31-2672-47fd-9baa-6c35f093a800&amp;name=Sat"><h3>Sat</h3></a>

Conclusion

Solution under number 3 is your best bet. Binding and unbinding can be process demanding.

Community
  • 1
  • 1
Gajotres
  • 57,309
  • 16
  • 102
  • 130
0

I usually use a namespace.

$('.selector').unbind('change.namespace').bind('change.namespace', function () {

Since I used the namespace to bind it, I can remove it from all elements with that namespace without worrying about removing other handlers.

Rusty Jeans
  • 1,426
  • 9
  • 10
  • yes, but this would require another "unbinding", which I don't want to use (too much bind/unbinds). I just want to set once. – frequent Mar 14 '13 at 16:54