The first thing you learn in jQuery is to call code inside the $(document).ready() so everything inside can execute as soon as DOM is loaded. However, in jQuery Mobile, Ajax is used to load the content of each page into the DOM as you navigate.
 
Because of this, $(document).ready() will/may trigger before your first page is loaded and every code intended for a page manipulation will execute only after a page refresh. This can be a very subtle problem. On some systems, it may appear that it works fine, but on others it may cause strange, difficult to repeat weirdness to occur.
 
 

Note: If this tutorial was helpful, need further clarification, something is not working or do you have a request for another Ionic post? Furthermore, if you don't like something about this blog, if something is bugging you, don't like how I'm doing stuff here, again leave me a comment below. I'm here to help you, I expect the same from you. Feel free to comment below, subscribe to my blog, mail me to dragan.gaic@gmail.com, or follow and mention me on twitter (@gajotres). Thanks and have a nice day!


 
Classic jQuery syntax:
 
$(document).ready(function() {

});
 
To solve this problem (and trust me this is a problem) jQuery Mobile developers have created something called page events. In a nutshell, page events are loading states triggered during the particular point of page execution. One of those page events is a pageinit event and it can be used like this:
 
$(document).on('pageinit', function(){

});
 
We can go even further and use a page id instead of document selector. Let’s say we have jQuery Mobile page with an id #index:
 
<div data-role="page" id="index">
    <div data-theme="a" data-role="header">
        <h4>
            First Page
        </h4>
        <a href="#second" class="ui-btn-right">Next</a>
    </div>

    <div data-role="content">
        <a href="#" data-role="button" id="test-button">Test button</a>
    </div>

    <div data-theme="a" data-role="footer" data-position="fixed">

    </div>
</div>
 
To execute a code that will only available to the index page we would use this syntax:
 
$(document).on('pageinit', '#index' ,function(){
    // Code goes here
});
 
The pageinit event will be trigger only when a page is about to be shown for the first time. It will not trigger again unless a page is manually refreshed or ajax page loading is turned off. In case you want code to execute every time you visit a page it is better to use pagebeforeshow or pageshow event.
 
Here’s a working example : http://jsfiddle.net/Gajotres/Q3Usv/ to demonstrate this case.
 
Few more notes on this question. No matter if you are using 1 HTML multiple pages or multiple HTML files templates, it is advised to gather all of your custom javascript page handling into a single separate js file. This will not make your code any better, but you will have much better code overview, especially while creating a jQuery Mobile application.
 
While not directly related to this topic it is good to understand how jQuery Mobile handles its javascript. When multiple HTML templates are used, only the first HTML page will be fully loaded into the DOM. Every other page will be loaded only partially. Only DIV containing page content will be loaded, and everything else, including the HEAD will be discarded. This is the main reason it is good to gather all of your js into a one single javascript file loaded into the first HTML file.
 
Of course there are some other solutions to this problem and they can be found in my other article.
 
There’s also one special jQuery Mobile event called mobileinit. When jQuery Mobile initializes, it requires mobileinit event triggered just after jQuery is initialized. It is used if some default setting needs to be overridden. One of the good examples of its usage is turning off classic ajax page loading, or changing default ajax loader behavior.
 
$(document).on("mobileinit", function(){
  //apply overrides here
});
 
This is when mobileinit event must be initialized:
 
<script src="jquery.js"></script>
<script>
$(document).on("mobileinit", function(){
  //apply overrides here
});
</script>
<script src="jquery-mobile.js"></script>
 

Page events transition order

 
First all events can be found here: http://api.jquerymobile.com/category/events/
 
Let’s say we have a page A and a page B, this is a unload/load order:
 

 
For better page events understanding read this:
 
pagebeforeload, pageload and pageloadfailed are fired when an external page is loaded with function called $.mobile.loadPage pagebeforechange, pagechange and pagechangefailed are page change events. These events are fired when a user is navigating between pages in the applications. pagebeforeshow, pagebeforehide, pageshow and pagehide are page transition events. These events are fired before, during and after a transition and are named. pagebeforecreate, pagecreate and pageinit are used for page initialization, and they will trigger ONLY once, unless page is refreshed. First two are excellent for dynamic content generation because jQuery Mobile will style page content only after pagecreate is executed. pageremove can be fired and then handled when a page is removed from the DOM
 
Page loading jsFiddle example: http://jsfiddle.net/Gajotres/QGnft/
 
It is good to know that if AJAX is not enabled, some events will not fire.
 

Prevent page transition

 
When talking about page events it is good to know how someone can prevent page transition, for every reason it may be:
 
$(document).on('pagebeforechange', function(e, data){  
    var to = data.toPage,
        from = data.options.fromPage;

    if (typeof to  === 'string') {
        var u = $.mobile.path.parseUrl(to);
        to = u.hash || '#' + u.pathname.substring(1);
        if (from) from = '#' + from.attr('id');

        if (from === '#index' && to === '#second') {
            alert('Can not transition from #index to #second!');
            e.preventDefault();
            e.stopPropagation();

            // remove active status on a button if transition was triggered with a button
            $.mobile.activePage.find('.ui-btn-active').removeClass('ui-btn-active ui-focus ui-btn');;
        }  
    }
});
 
This example will work in any case because it will trigger at a begging of every page transition and what is most important it will prevent page change before page transition can occur.
 

Prevent multiple event binding/triggering

 
Because of interesting jQM loading architecture, multiple event triggering is a constant problem. For example, take a look at this code snippet:
 
$(document).on('pagebeforeshow','#index' ,function(e,data){    
    $(document).on('click', '#test-button',function(e) {
        alert('Button click');
    });    
});
 
Working jsFiddle example: http://jsfiddle.net/Gajotres/CCfL4/
 
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 an event before you bind it:
 
$('#index').live('pagebeforeshow',function(e,data){    
    $('#test-button').die().live('click', function(e) {
        alert('Button click');
    });    
});
 
Working jsFiddle example: http://jsfiddle.net/Gajotres/K8YmG/
 
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 than Solution 1.
 

Solution 3:

 
A new one, 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/
 
Tnx to the sholsinger for this solution: http://sholsinger.com/archive/2011/08/prevent-jquery-live-handlers-from-firing-multiple-times/
 
Continue Reading

  • jrraymond

    great post! Thank you very much.

  • Ralf-J.

    You’ve really made my day! I’m working with jQuery Mobile as one possible framework in a designer tool for SAP. That means that i don’t work with jQuery Mobile every day, just now and then. It has cost me days to figure out when to use which event and why. Your post clears everything up and the examples are really great. Many thanks!

  • kasahs

    Thank you this was very helpful!

  • http://www.sure-sense.com Glenn Smith

    This is an awesome post. It clearly describes how these features of JQuery Mobile interact with the DOM and gives practical advice on how to use them. This is not that clear from the JQuery Mobile documentation, this post should be linked to in that verbatim. Thanks.

  • Anderson

    In the section “page events transition order”, event pagebeforeshow of page B occurs twice! Something wrong?

  • maarten

    I am new to jQuery Mobile. This article should be obligated to everyone like me. Thank you very much!

  • http://www.dragan-gaic.info Gajotres

    @Anderson: Thank you for this comment, it was a typo.

  • James

    Hey man, just stumbled on this article via Stack Overflow. Thank you so much, I was having crazy scripting problems in the first app I’m writing and this totally solved it – good work!

  • Ravi

    Great post to address basic jquery Mobile issues.

  • http://davidpich.com David Pich

    Thanks for your article! Awesome post ! Congrats!

    • http://www.dragan-gaic.info Gajotres

      Thank you!

  • http://forexreviewjournal.com/ Pini Soliman

    Thank you very much for this useful material.

  • Pingback: JQuery Mobile != Jquery – Vikram Shetty()

  • Janell

    I have 3 pages with the same structure and two footers that go to id=1 and id=2 for each page. How would this code:

    $(document).on(‘pagebeforeshow’, “#index”,function () {
    $(document).on(‘click’, “#changePage”,function () {
    $.mobile.changePage(‘second.html’, { dataUrl : “second.html?paremeter=123”, data : { ‘paremeter’ : ‘123’ }, reloadPage : false, changeHash : true });
    });
    });

    $(document).on(‘pagebeforeshow’, “#second”,function () {
    var parameters = $(this).data(“url”).split(“?”)[1];;
    parameter = parameters.replace(“parameter=”,””);
    alert(parameter);
    });

    work for 3 pages? (Unfortunately I don’t know Javascript, least not yet.)
    Thanks so much for any help you can give me!!!!!
    Janell

  • Matt

    Congratulations for this amazing post, with information I couldn’t find anywhere else. Very clear, thank you !

  • Bob Langdon

    Fantastic stuff!
    Especially the explanations of page events and related issues.
    I’ve been beating my head against the wall trying to figure out why forms keep executing, and alert boxes are stuck in loops!
    LOL
    VERY helpful.
    THANKS!

  • David

    Thanks a lot for all your explanations… very clear to understand…. more than JqueryMobile official web site

    I wondered why my javascript where not ran into my Head section and it is clear now

    Thanks

    David