Sebastian
Sebastian

Reputation: 313

JQueryMobile listen click

I am trying to understand the page events in jQueryMobile navigation, but I found some very weird behaviour, as some event handlers get called several times:

I have two pages: home.html and disclaimer.html. Both contain the same header:

<head>
    <script src="js/jquery-1.8.2.min.js"></script>
    <script src="js/events.js"></script>
    <script src="js/jquery.mobile-1.2.0.min.js"></script>
</head>

On the page home.html is a link:

<section data-role="page" id="home">
    <a href="#" id="test">Test</a>
</section>

And in the file events.js is the following code:

var i = 0;

$(document).on('pageinit', 'section#home', function(event) {
    console.log(i++, 'pageinit');
    $('a#test').on('click', function() {
        console.log(i++, 'click pageinit');
    });
});

$(document).on('pagebeforeshow', 'section#home', function(event) {
    console.log(i++, 'pagebeforeshow');
    $('a#test').on('click', function() {
        console.log(i++, 'click pagebeforeshow');
    });
});

Then I do the following steps:

  1. Navigate to home.html (http)
  2. Click the link
  3. Go to disclaimer.html (ajax)
  4. Go to home.html (ajax)
  5. Click the link

With the following console output:

0 "pageinit"             // step 1
1 "pagebeforeshow"
2 "click pageinit"       // step 2
3 "click pagebeforeshow"
4 "pagebeforeshow"       // step 4
5 "click pageinit"       // step 5
6 "click pagebeforeshow"
7 "click pagebeforeshow" 

Makes sense, right? But now the weird part. When I change the order in which I visit the pages: the behaviour changes.

  1. Navigate to disclaimer.html (http)
  2. Go to home.html (ajax)
  3. Click the link
  4. Go to disclaimer.html (ajax)
  5. Go to home.html (ajax)
  6. Click the link

Console output:

0 "pageinit"             // step 2
1 "pagebeforeshow"
2 "click pageinit"       // step 3
3 "click pagebeforeshow"
4 "pageinit"             // step 5
5 "pagebeforeshow"
6 "click pageinit"       // step 6
7 "click pagebeforeshow" 

Which is weird, because I would expect the 6th and 7th result to have been duplicated.

Sorry for the very long question. I hope someone can explain to me exactly what is happening and if this is expected behaviour?

tldr; Where do you listen for (click) events in jQueryMobile?

Upvotes: 2

Views: 953

Answers (1)

Roimer
Roimer

Reputation: 1459

In short: in jQueryMobile you should listen (bind) your events inside pageinit; this is equivalent (more of less) to jQuery's ready event. And it is what the jQueryMobile's guys recommend.

pageinit is triggered once the page has been loaded and initialized (via AJAX or HTTP), but pagebeforeshow may be triggered more than once if the page is already in the DOM, for example after closing a jQueryMobile dialog. Whatever you bind on pagebeforeshow is going to be rebind again every time the page is showed again. That is why you have two click pagebeforeshow.

EDIT: Explanation of your tests

I replicated your 2 html pages and js file and repeated all the steps in both tests.

In your first test you have:

  1. Navigate to home.html (http): It binds (by delegating on document) and triggers pageinit and pagebeforeshow (logs 0 and 1) because your page was initialized and was going to be shown. this also binds the oter two functions to the link (important: in this case is not delegation, but a direct bind!). This is the only time in this test in which "events.js" is going to be loaded and executed.
  2. Click the link: this executes both click pageinit and click pagebeforeshow as expected (logs 2 and 3) because step 1.
  3. Go to disclaimer.html (ajax): this doesn't show any log.
  4. Go to home.html (ajax): since "home.html" is still in the DOM this triggers pagebeforeshow, as you can see in log (4). This executes too the binding in the link. NOTE: I suspect that at this step "disclaimer.html" was remove from DOM (more on this in second test).
  5. Click the link: shows tree logs, the first 2 because step 1, and the last (duplicated) because step 4.

In your second test you have:

  1. Navigate to disclaimer.html (http): It binds pageinit and pagebeforeshow, but doesn't show a log since none of the event is being triggered; both events are being bind to document (by delegation), so it doesn't matters if the specific page isn't yet in the DOM. This is the only time in this test in which "events.js" is going to be loaded and executed.
  2. Go to home.html (ajax): It triggers pageinit and pagebeforeshow and you can see logs 0 and 1. When both events are triggered, the corresponding click events are being bind to the link (a direct bind!)
  3. Click the link: This step shows logs 2 and 3, as expected.
  4. Go to disclaimer.html (ajax): Nothing is shown in the log... but: jQueryMobile decided that "home.html" should be removed from DOM! that is because JQM removes every page once you navigate to another one. Note that "disclaimer.html" is not going to be removed from the DOM ever, since he is the "owner" of it.
  5. Go to home.html (ajax): this step triggers pageinit and pagebeforeshow (since both events are still bind to the document object) as you can see in logs 4 and 5. This binds the two functions to the link, just as in step 2, but... (see next step)
  6. Click the link: Here is where you said "I would expect the 6th and 7th result to have been duplicated"; well they weren't duplicated because the whole page (the div containing the link) and all its content where removed from the DOM, and the first click events you bind directly to the link (in step 2) are gone! so you see only the logs caused by the bind in step 5.

If I (finally) understood how JQM events work, the first page loaded (via full HTTP request) is kept in the DOM until the user navigate to an external page or reload the page (via F5 or CTRL+R). Any other page (loaded via AJAX) is added to the "main" DOM and then unloaded/deleted from it when you navigate to another one. So: if you do all your binds in pageinit (direct binds or at most delegating to its parent div[data-role:page]) you won't need to worry about duplicated event binds.

PD: If you note something weird in how I write, is probably because I'm not used to speak/write in English in passive voice, and sometimes I mix up prepositions :P

Upvotes: 1

Related Questions