Search code examples
javascriptjqueryjquery-mobilebindingjquery-events

How do I unbind events properly when using allowSamePageTransition in jQuery Mobile?


I'm using the jQuery Mobile option allowSamePageTransition, which enables me to go from

page A > page A > page A ...

I need this to allow browsing through a catalogue of items. My problem is, the items need some form of interaction and I used to attach the interaction binding to document, because it is set before the elements affected are generated.

However, reloading the same page over and over again will re-bind my event handlers every time I reload.

My first idea was to use .off when the page is being hidden, but reloading a page #foo, will trigger pagehide on the same page being shown, so all bindings set on

$(document).on("pagebeforeshow.foo_events", "#foo", function(e) {
  // bind when shown
});

will be unbound again by the previous #foo being hidden

$(document).on("pagehide", "#foo", function (e) {
  $(this).off(".foo_events");
  // removes bindings on #foo being hidden AND shown
});

The only solution I have come up with is plastering the document with classes, which I don't like doing:

priv.setBindings = function (param) {
    var doc = $(document);

  doc
    .filter(function() { return $(this).is(".e_gallery") !== true; })
    .on("pagebeforeshow.gallery", param.pageId, function (e) {
      doc.addClass(".e_gallery");
      // run stuff
    });
};

But I'm no fan of attaching classes to the dom.

Question:
Is there a way to prevent multiple event bindings set on $(document) when going to the same page over and over again WITHOUT toggling classes?


Solution

  • Solution 1

    Best solution would be to use pageinit to bind events. If you take a look at an official documentation you will find out that pageinit will trigger ONLY once, just like document ready, so there's no way events will be bound again. This is best solution because you don't have processing overhead like when removing events with off method.

    Working jsFiddle example: http://jsfiddle.net/Gajotres/AAFH8/

    Of course this will fail in case multiple HTML solution is used.

    Solution 2

    Remove event before you bind it:

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

    Working jsFiddle example: http://jsfiddle.net/Gajotres/K8YmG/

    Solution 3

    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/

    This is probably best solution because event is going to be bound ONLY once.

    Solution 4

    Probably an easiest of them all.

    $(document).on('pagebeforeshow', '#index', function(){       
        $(document).on('click', '#test-button',function(e) {
            if(e.handled !== true) // This will prevent event triggering more then once
            {
                alert('Clicked');
                e.handled = true;
            }
        }); 
    });
    

    Working jsFiddle example: http://jsfiddle.net/Gajotres/Yerv9/

    This is a 180 percent different solution then solution 3, in this case event is going to be bound numerous times but it will be allowed to execute only once.

    More info

    If you want to find more about this problem take a look at this article, working examples are included.