Reputation: 313
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:
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.
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
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.
I replicated your 2 html pages and js file and repeated all the steps in both tests.
In your first test you have:
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.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). In your second test you have:
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.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!)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)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