Rectangle 27 12

I found the solution. I needed to initialize the Google map in the "pagecreate" jQuery Mobile event instead of on $(document).ready. I also had a problem with the full map not rendering properly everytime the page showed so I solved that by calling google.maps.event.trigger(map, 'resize') to refresh the map on the "pageshow" jQuery Mobile event.

<!DOCTYPE html>
<html>
<head>
    <title>Index</title>
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a2/jquery.mobile-1.0a2.min.css" />
    <script src="http://code.jquery.com/jquery-1.4.4.min.js"></script>
    <script src="http://maps.google.com/maps/api/js?sensor=false"></script>
    <script src="http://code.jquery.com/mobile/1.0a2/jquery.mobile-1.0a2.min.js"></script>
    <style type="text/css"> 
        .gmap { height: 330px; width: 100%; margin: 0px; padding: 0px }
    </style>
</head>

<body>
    <div data-role="page">

    <div data-role="header">
        <h1>jQuery Mobile</h1>
    </div>

    <div data-role="content">
    <ul data-role='listview' id='menu'>
        <li><a href="pages/map1.html">external map page 1</a></li>
        <li><a href="pages/map2.html">external map page 2</a></li>
    </ul>
    </div>

</div>


</body>
</html>
<div data-role="page" class="page-map2">

    <div data-role="header">
        <h1>jQuery Mobile</h1>
    </div>

    <div data-role="content">

    <h2>Map</h2>

    <div id="map2" class="gmap"></div>

    <script type="text/javascript">
        var map2, latlng2, options2;
        function initialize() {

            latlng2 = new google.maps.LatLng(40.716948, -74.003563);
            options2 = { zoom: 14, center: latlng2, mapTypeId: google.maps.MapTypeId.ROADMAP };
            map2 = new google.maps.Map(document.getElementById("map2"), options2);

        }
        $('.page-map2').live("pagecreate", function() {

            initialize();

        });

        $('.page-map2').live('pageshow',function(){

            google.maps.event.trigger(map2, 'resize');
            map2.setOptions(options2); 
        });

    </script> 

    </div>
</div>

jQuery Mobile - How to implement Google Maps on Externally Linked Page...

jquery mobile maps
Rectangle 27 1

Annotate the page and the dialog with a unique id and bind something like this to the pageshow event of the page:

jQuery('#myPageId').bind('pageshow', function() {
    var me = jQuery(this);
    var dialogShown = me.data('dialogShown');
    var dialog = jQuery('#myDialogId');
    if(!dialogShown) {
        me.data('dialogShown', true);
        dialog.one('pageshow', function() {
            setTimeout(function() { window.history.back(); }, '3000');
        });
        jQuery.mobile.changePage(dialog, {transition: 'fade'}); 
    }
});

jQuery Mobile close dialog and load a different page - Stack Overflow

jquery jquery-mobile
Rectangle 27 3

pageinit will fire when your page first loads. Both of your pages are cached within the DOM so that event will only fire once. Try pageshow which will fire each time the page is shown.

Also, live() is depreciated. You should use bind() or on().

$("#page1").bind('pageshow', function () {
    $("#page1_output").append('<br/> page 1 initialized. time - ' + new Date());
});


$("#page2").bind('pageshow', function () {
    $("#page2_output").append('<br/> page 2 initialized time - ' + new Date());
});

you would think binding to pageload event would work but it doesn't. pageshow works though

as far as on function, the page is using jquery 1.6.4 so it's not available. i'll upgrade jquery and use `on' instead. thanks

I have no idea how they came up with the page event names but pageload could also be confusing. Was the page loaded from cache or from the server? Glad I was able to solve your issue.

jQuery Mobile - pageinit handler not called on subsequent changePage c...

jquery-mobile
Rectangle 27 3

jQuery Moible has a problem with web-kit browsers, so if any page event (except pageshow) is used, ajax loader will only work if executed with setinterval:

$(document).on('pagebeforeshow', '#index', function(){  
    var loader = setInterval(function(){
        $.mobile.loading('show');
        clearInterval(loader);
    },1);       
});

As I have mentioned earlier ajax loader will be successfully shown in Chrome and Safari ig pageshow event is used, example: http://jsfiddle.net/8ay3W/1/

This code can also be safely used in Firefox and mobile browsers.

This was specific to Chrome and Safari from the first jQM version, no matter using the old version of alax loader triggering or this new one with $.mobile.loading('show').

There are few other similar problems. This is also the only way jQM popup can be programatically turned on/off.

function showSpinner(){       var loader = setInterval(function(){         $.mobile.loading('show');         clearInterval(loader);     },1); }
function heavyTask(){ showSpinner(); }

jQuery mobile loading wheel does not works in some browsers - Stack Ov...

jquery jquery-ui jquery-mobile setinterval clearinterval
Rectangle 27 1

$(document).on('pageshow', "div[data-role='page']", function () {
    $(window).trigger('resize');
});

It has an improvement that apply to all the jquery mobile pages

pageshow
pagecontainershow
$(document).on( ... function() { setTimeout( function() { $(window).trigger('resize'); }, 100 /*ms*/ ); });
100
$(window).on('load', function() ...

Image in jquery mobile fixed header overlaps content until resize even...

jquery-mobile
Rectangle 27 3

Depending on when your code runs it may be running before the jQuery Mobile initialization process. jsFiddle by default runs code after the load event fires so the DOM is all setup and jQuery Mobile has done its initialization. If you change @Phill Pafford's jsFiddle (http://jsfiddle.net/qSmJq/3/) to run on "no wrap (body)" rather than "onLoad" then you get the same error you are reporting. So I recommend either removing the lists.listview('refresh'); line or putting your code inside either a document.ready or a pageshow/pagecreate event handler:

var lists = $( '#posicaoIntegradaActivosList, #posicaoIntegradaPassivosList, #posicaoIntegradaOutrosList' );

lists.empty();

/* Fill the lists with jquery template */

//lists.listview( "refresh" );

Here's a jsfiddle for running the code as soon as it is parsed by the browser: http://jsfiddle.net/jasper/qSmJq/5/

$(function () {
    var lists = $( '#posicaoIntegradaActivosList, #posicaoIntegradaPassivosList, #posicaoIntegradaOutrosList' );

    lists.empty();

    /* Fill the lists with jquery template */

    lists.listview( "refresh" );
}
document.ready
$('#my-page-id').on('pagecreate', function () {
    var lists = $( '#posicaoIntegradaActivosList, #posicaoIntegradaPassivosList, #posicaoIntegradaOutrosList' );

    lists.empty();

    /* Fill the lists with jquery template */

    //lists.listview( "refresh" );
}
pageshow
pagecreate

On a side note: if you want to detect whether or not jQuery Mobile has initialized a certain element you can check for the jQuery Mobile specific classes on the element:

$(function () {

    //cache lists
    var lists = $( '#posicaoIntegradaActivosList, #posicaoIntegradaPassivosList, #posicaoIntegradaOutrosList' );

    //iterate through the lists
    lists.each(function (index, value) {

        //cache this specific list
        var $value = $(value);

        /*add rows to this listview here*/

        //check if the listview has been initialized by jQuery Mobile by checking for the existence of the `ui-listview` class
        if ($value.hasClass('ui-listview')) {

            //since the class was found, refresh the already initialized element
            $value.listview('refresh');
        } else {

            //the class was not found, so initialize the widget
            $value.trigger('create');
        }
    });
});

Jasper, I followed your logic and it worked. The problem was that, at the time that I was tryign to refresh to listview, the widget wasn't even created so the code ended up like: $( lists ).each( function() { ( $( this ).hasClass( 'ui-listview' ) ) ? $( this ).listview( 'refresh' ) : $( this ).trigger( 'create' ); }); Thank you very much!

I'm happy to have helped.

javascript - Refresh listview with jQuery mobile version 1.0rc3 - Stac...

javascript jquery listview mobile jquery-mobile
Rectangle 27 1

Just like Android activity lifecycle. jQuery Mobile pages have different events. You can check out the list of events from the official documentation for jQuery Mobile 1.3.0.

pagebeforeshow
pageshow
pagecreate

javascript - jQuery Mobile -> Page Lifecycle? - Stack Overflow

javascript jquery jquery-mobile page-lifecycle
Rectangle 27 1

1. use one() instead of bind() or live() As long as the page is not dropped from the DOM, this should help. See here.

Jquery Mobile uses it inside JQM too, probably for the same reason. So if you do like this:

$('button').one('click', function () { do something });

2. Use data() to set a flag after event is fired Another idea would be to use data() to attach a flag to the page element or, as pages can be removed from the DOM, better attach it to the HTML or BODY element. These will stay...

$('div[data-role="page"]').live('pagebeforeshow.scroll', function(event){
     var $page = $(this);
     if ( $page.data('scrollable', 'Off') ) {
         $page.data('scrollable', 'On');
         scrollMe( $page ); // init
         }
      });

This would probably mean putting your function call outside of the actual page.

This also works for me using attr:

// on pageinit - set global argument
    $('html').attr('fire-once', 'Off'); 

    $( '#your page' ).live( 'pageshow',function(event){
    if ( $('html').attr('fire-once') == 'Off' ) {
            $('html').attr('fire-once', 'On');
            // your button.bind.behavior here
            }
       });

This way you set "fire-once" on the HTML element, which will always stay the same in JQM while you load pages in and out. Only if you go to a page with data-rel="external", fire-once will be reset.

On your specified page you listen for pageshow, fire the function, that first changes fire-once to "On" and then adds your button binding.

Since fire-once is now turned "On", even with multiple bindings the if-statement will fail and you will only assign the button behavior once.

I'm using the same setup with a JQM-panel history-array, which I need to setup only once and only add entries on changePage once, too. The above works fine for me and should also serve your purpose.

Send me a message, if you want to see a live example.

Yeah I like this even better than the live/die, forgot about this method, a lot more elegant.

Thx. But I afraid it won't serve my purpose, as I want if user click on button and tht btn make ajax call, if user click on it each time ajax call should be made. .one will defy this. My problem is on each ajax-visit to the page, .click get binded, so in second visit single click cause 2 time execution of method binded to click.

c# - ASP.NET MVC3 jQuery mobile page's Ajax code binding using PageIni...

c# javascript asp.net-mvc jquery-mobile
Rectangle 27 430

My original article was intended for old way of page handling, basically everything before jQuery Mobile 1.4. Old way of handling is now deprecated and it will stay active until (including) jQuery Mobile 1.5, so you can still use everything mentioned below, at least until next year and jQuery Mobile 1.6.

Old events, including pageinit don't exist any more, they are replaced with pagecontainer widget. Pageinit is erased completely and you can use pagecreate instead, that event stayed the same and its not going to be changed.

If you are interested in new way of page event handling take a look here, in any other case feel free to continue with this article. You should read this answer even if you are using jQuery Mobile 1.4 +, it goes beyond page events so you will probably find a lot of useful information.

This article can also be found as a part of my blog HERE.

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

$(document).ready(function() {

});

To solve this problem (and trust me this is a problem) jQuery Mobile developers created page events. In a nutshell page events are events triggered in a particular point of page execution. One of those page events is a pageinit event and we can use it 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">
        <h3>
            First Page
        </h3>
        <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 code that will only available to the index page we could use this syntax:

$('#index').on('pageinit', function() {

});

Pageinit event will be executed every time page is about be be loaded and shown for the first time. It will not trigger again unless 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 event.

Few more notes on this question. No matter if you are using 1 html multiple pages or multiple HTML files paradigm it is advised to separate all of your custom JavaScript page handling into a single separate JavaScript file. This will note make your code any better but you will have much better code overview, especially while creating a jQuery Mobile application.

There's also another special jQuery Mobile event and it is called mobileinit. When jQuery Mobile starts, it triggers a mobileinit event on the document object. To override default settings, bind them to mobileinit. One of a good examples of mobileinit usage is turning off Ajax page loading, or changing default Ajax loader behavior.

$(document).on("mobileinit", function(){
  //apply overrides here
});

Lets say we have a page A and a page B, this is a unload/load order:

  • pagebeforeload, pageload and pageloadfailed are fired when an external page is loaded
  • 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 for page initialization.
  • pageremove can be fired and then handled when a page is removed from the DOM

If AJAX is not enabled, some events may not fire.

$(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.

Here's a working example:

jQuery Mobile works in a different way than classic web applications. Depending on how you managed to bind your events each time you visit some page it will bind events over and over. This is not an error, it is simply how jQuery Mobile handles its pages. For example, take a look at this code snippet:

Each time you visit page #index click event will is going to be bound to button #test-button. Test it by moving from page 1 to page 2 and back several times. There are few ways to prevent this problem:

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.

This working solution is made on a basis of a previous problematic example.

Use a jQuery Filter selector, like this:

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

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

A new one, probably an easiest of them all.

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.

<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>

As mentioned, when you change from one jQuery Mobile page to another, typically either through clicking on a link to another jQuery Mobile page that already exists in the DOM, or by manually calling $.mobile.changePage, several events and subsequent actions occur. At a high level the following actions occur:

  • The content for that page is enhanced (styled)
  • A transition (slide/pop/etc) from the existing page to the new page occurs

*These values are in milliseconds.

So as you can see a transition event is eating almost 90% of execution time.

It is possible to send a parameter/s from one page to another during page transition. It can be done in few ways.

You can pass values with changePage:

$.mobile.changePage('page2.html', { dataUrl : "page2.html?paremeter=123", data : { 'paremeter' : '123' }, reloadPage : true, changeHash : true });
<!DOCTYPE html>
  <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="widdiv=device-widdiv, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-status-bar-style" content="black" />
    <title>
    </title>
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" />
    <script src="http://www.dragan-gaic.info/js/jquery-1.8.2.min.js">
    </script>
    <script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script>
   </head>
   <body>
    <!-- Home -->
    <div data-role="page" id="second">
        <div data-role="header">
            <h3>
                Second Page
            </h3>
        </div>
        <div data-role="content">

        </div> <!--content-->
    </div><!--page-->

  </body>
</html>

Or you can create a persistent JavaScript object for a storage purpose. As long Ajax is used for page loading (and page is not reloaded in any way) that object will stay active.

var storeObject = {
    firstname : '',
    lastname : ''
}

You can also access data from the previous page like this:

$(document).on('pagebeforeshow', '#index',function (e, data) {
    alert(data.prevPage.attr('id'));
});

prevPage object holds a complete previous page.

As a last solution we have a nifty HTML implementation of localStorage. It only works with HTML5 browsers (including Android and iOS browsers) but all stored data is persistent through page refresh.

if(typeof(Storage)!=="undefined") {
    localStorage.firstname="Dragan";
    localStorage.lastname="Gaic";
}

Probably best solution but it will fail in some versions of iOS5.X. It is a well know error.

I forgot to mention (and tnx andleer for reminding me) use on/off for event binding/unbinding, live/die and bind/unbind are deprecated.

The .live() method of jQuery was seen as a godsend when it was introduced to the API in version 1.3. In a typical jQuery app there can be a lot of DOM manipulation and it can become very tedious to hook and unhook as elements come and go. The .live() method made it possible to hook an event for the life of the app based on its selector. Great right? Wrong, the .live() method is extremely slow. The .live() method actually hooks its events to the document object, which means that the event must bubble up from the element that generated the event until it reaches the document. This can be amazingly time consuming.

It is now deprecated. The folks on the jQuery team no longer recommend its use and neither do I. Even though it can be tedious to hook and unhook events, your code will be much faster without the .live() method than with it.

Instead of .live() you should use .on(). .on() is about 2-3x faster than .live(). Take a look at this event binding benchmark: http://jsperf.com/jquery-live-vs-delegate-vs-on/34, everything will be clear from there.

There's an excellent script made for jQuery Mobile page events benchmarking. It can be found here: https://github.com/jquery/jquery-mobile/blob/master/tools/page-change-time.js. But before you do anything with it I advise you to remove its alert notification system (each change page is going to show you this data by halting the app) and change it to console.log function.

Basically this script will log all your page events and if you read this article carefully (page events descriptions) you will know how much time jQm spent of page enhancements, page transitions ....

Always, and I mean always read official jQuery Mobile documentation. It will usually provide you with needed information, and unlike some other documentation this one is rather good, with enough explanations and code examples.

  • 30.01.2013 - Added a new method of multiple event triggering prevention
  • 22.05.2013 - Added a solution for page transition/change prevention and added links to the official page events API documentation
  • 18.05.2013 - Added another solution against multiple event binding

$().live() was depreciated in jQuery 1.7 and removed in 1.9 so it really should be part of any jQuery Mobile solution. The current minimum core version for jQM 1.7.

+1 very helpful summary of critical behaviours around page loads

pagecreate event is fired only once when page first created. so if we bind click events inside pagecreate it'll not fire multiple times. Something I figured out while developing the app. But we can't always use pagecreate to bind events so the solution you gave is the best. +1 given

You have pageBeforeShow listed twice. It's listed as number 5 and number 8. Does it get called twice?

That was a typo, I've fixed it, pagebeforeshow will trigger only once. Thanks for noticing it.

javascript - jQuery Mobile: document ready vs. page events - Stack Ove...

javascript jquery html5 jquery-mobile cordova
Rectangle 27 429

My original article was intended for old way of page handling, basically everything before jQuery Mobile 1.4. Old way of handling is now deprecated and it will stay active until (including) jQuery Mobile 1.5, so you can still use everything mentioned below, at least until next year and jQuery Mobile 1.6.

Old events, including pageinit don't exist any more, they are replaced with pagecontainer widget. Pageinit is erased completely and you can use pagecreate instead, that event stayed the same and its not going to be changed.

If you are interested in new way of page event handling take a look here, in any other case feel free to continue with this article. You should read this answer even if you are using jQuery Mobile 1.4 +, it goes beyond page events so you will probably find a lot of useful information.

This article can also be found as a part of my blog HERE.

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

$(document).ready(function() {

});

To solve this problem (and trust me this is a problem) jQuery Mobile developers created page events. In a nutshell page events are events triggered in a particular point of page execution. One of those page events is a pageinit event and we can use it 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">
        <h3>
            First Page
        </h3>
        <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 code that will only available to the index page we could use this syntax:

$('#index').on('pageinit', function() {

});

Pageinit event will be executed every time page is about be be loaded and shown for the first time. It will not trigger again unless 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 event.

Few more notes on this question. No matter if you are using 1 html multiple pages or multiple HTML files paradigm it is advised to separate all of your custom JavaScript page handling into a single separate JavaScript file. This will note make your code any better but you will have much better code overview, especially while creating a jQuery Mobile application.

There's also another special jQuery Mobile event and it is called mobileinit. When jQuery Mobile starts, it triggers a mobileinit event on the document object. To override default settings, bind them to mobileinit. One of a good examples of mobileinit usage is turning off Ajax page loading, or changing default Ajax loader behavior.

$(document).on("mobileinit", function(){
  //apply overrides here
});

Lets say we have a page A and a page B, this is a unload/load order:

  • pagebeforeload, pageload and pageloadfailed are fired when an external page is loaded
  • 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 for page initialization.
  • pageremove can be fired and then handled when a page is removed from the DOM

If AJAX is not enabled, some events may not fire.

$(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.

Here's a working example:

jQuery Mobile works in a different way than classic web applications. Depending on how you managed to bind your events each time you visit some page it will bind events over and over. This is not an error, it is simply how jQuery Mobile handles its pages. For example, take a look at this code snippet:

Each time you visit page #index click event will is going to be bound to button #test-button. Test it by moving from page 1 to page 2 and back several times. There are few ways to prevent this problem:

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.

This working solution is made on a basis of a previous problematic example.

Use a jQuery Filter selector, like this:

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

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

A new one, probably an easiest of them all.

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.

<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>

As mentioned, when you change from one jQuery Mobile page to another, typically either through clicking on a link to another jQuery Mobile page that already exists in the DOM, or by manually calling $.mobile.changePage, several events and subsequent actions occur. At a high level the following actions occur:

  • The content for that page is enhanced (styled)
  • A transition (slide/pop/etc) from the existing page to the new page occurs

*These values are in milliseconds.

So as you can see a transition event is eating almost 90% of execution time.

It is possible to send a parameter/s from one page to another during page transition. It can be done in few ways.

You can pass values with changePage:

$.mobile.changePage('page2.html', { dataUrl : "page2.html?paremeter=123", data : { 'paremeter' : '123' }, reloadPage : true, changeHash : true });
<!DOCTYPE html>
  <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="widdiv=device-widdiv, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-status-bar-style" content="black" />
    <title>
    </title>
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" />
    <script src="http://www.dragan-gaic.info/js/jquery-1.8.2.min.js">
    </script>
    <script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script>
   </head>
   <body>
    <!-- Home -->
    <div data-role="page" id="second">
        <div data-role="header">
            <h3>
                Second Page
            </h3>
        </div>
        <div data-role="content">

        </div> <!--content-->
    </div><!--page-->

  </body>
</html>

Or you can create a persistent JavaScript object for a storage purpose. As long Ajax is used for page loading (and page is not reloaded in any way) that object will stay active.

var storeObject = {
    firstname : '',
    lastname : ''
}

You can also access data from the previous page like this:

$(document).on('pagebeforeshow', '#index',function (e, data) {
    alert(data.prevPage.attr('id'));
});

prevPage object holds a complete previous page.

As a last solution we have a nifty HTML implementation of localStorage. It only works with HTML5 browsers (including Android and iOS browsers) but all stored data is persistent through page refresh.

if(typeof(Storage)!=="undefined") {
    localStorage.firstname="Dragan";
    localStorage.lastname="Gaic";
}

Probably best solution but it will fail in some versions of iOS5.X. It is a well know error.

I forgot to mention (and tnx andleer for reminding me) use on/off for event binding/unbinding, live/die and bind/unbind are deprecated.

The .live() method of jQuery was seen as a godsend when it was introduced to the API in version 1.3. In a typical jQuery app there can be a lot of DOM manipulation and it can become very tedious to hook and unhook as elements come and go. The .live() method made it possible to hook an event for the life of the app based on its selector. Great right? Wrong, the .live() method is extremely slow. The .live() method actually hooks its events to the document object, which means that the event must bubble up from the element that generated the event until it reaches the document. This can be amazingly time consuming.

It is now deprecated. The folks on the jQuery team no longer recommend its use and neither do I. Even though it can be tedious to hook and unhook events, your code will be much faster without the .live() method than with it.

Instead of .live() you should use .on(). .on() is about 2-3x faster than .live(). Take a look at this event binding benchmark: http://jsperf.com/jquery-live-vs-delegate-vs-on/34, everything will be clear from there.

There's an excellent script made for jQuery Mobile page events benchmarking. It can be found here: https://github.com/jquery/jquery-mobile/blob/master/tools/page-change-time.js. But before you do anything with it I advise you to remove its alert notification system (each change page is going to show you this data by halting the app) and change it to console.log function.

Basically this script will log all your page events and if you read this article carefully (page events descriptions) you will know how much time jQm spent of page enhancements, page transitions ....

Always, and I mean always read official jQuery Mobile documentation. It will usually provide you with needed information, and unlike some other documentation this one is rather good, with enough explanations and code examples.

  • 30.01.2013 - Added a new method of multiple event triggering prevention
  • 22.05.2013 - Added a solution for page transition/change prevention and added links to the official page events API documentation
  • 18.05.2013 - Added another solution against multiple event binding

$().live() was depreciated in jQuery 1.7 and removed in 1.9 so it really should be part of any jQuery Mobile solution. The current minimum core version for jQM 1.7.

+1 very helpful summary of critical behaviours around page loads

pagecreate event is fired only once when page first created. so if we bind click events inside pagecreate it'll not fire multiple times. Something I figured out while developing the app. But we can't always use pagecreate to bind events so the solution you gave is the best. +1 given

You have pageBeforeShow listed twice. It's listed as number 5 and number 8. Does it get called twice?

That was a typo, I've fixed it, pagebeforeshow will trigger only once. Thanks for noticing it.

javascript - jQuery Mobile: document ready vs. page events - Stack Ove...

javascript jquery html5 jquery-mobile cordova
Rectangle 27 4

In case your second page javascript is placed inside a HEAD content

If I understood you correctly, you are using ajax to load this page into the DOM? If this is true then I understand your problem. You see, when ajax is used for page loading only BODY content is loaded into the DOM.

You can fix your problem if you initialize your second html page javascript inside a first HTML file or move your SCRIPT block inside a second HTML BODY content.

Also, I have described this problem in my other ARTICLE with more details and few examples, or it can be found HERE.

This could also be a little different problem. You see, if you have 2 buttons with a same id, they are both inside a DOM structure. If you try to bind a click event on a second page button, that same event will be bound to the button on a first page. Because they have a same id jQuery will bound an event to the first button (with that id) found in the DOM.

To fix this problem you need to use a jQM constructor called active page. One more warning, next code example will work only in a page events initialized after a pageinit event, for example pagebeforeshow or pageshow events:

$(document).on('pagebeforeshow', '#yourPageID', function(){     
    // Registering button click  
    $(document).on('click', $.mobile.activePage.find('#myButtonID'), function(){
        // Do something
    });
});

This line of code:

$.mobile.activePage.find('#myButtonID')

Will only get button '#myButtonID' found in a current active page, no matter how many other buttons with a same id exist inside the DOM.

About your last questions. It doesn't matter which template structure you use (1 HTML with multiple pages or multiple HTML's), you just need to worry about things I mentioned before.

Phonegap - jquery Mobile : button click event not able catch in androi...

android jquery jquery-mobile cordova
Rectangle 27 24

All information found here can also be found in my blog ARTICLE, you will also find working examples.

A1 - Phonegap app/framework initialization with the deviceReady event.

document.addEventListener("deviceReady", yourCallbackFunction, false);

function deviceReady() {

}

A2 - jQuery Mobile app/framework initialization with the mobileinit event.

$(document).on("mobileinit", function () {

});

Lets say we have a page A and a page B, this is a unload/load order:

1. page B - event pagebeforecreate

2. page B - event pagecreate

3. page B - event pageinit

4. page A - event pagebeforehide

5. page B - event pagebeforeshow

6. page A - event pageremove

7. page A - event pagehide

8. page B - event pageshow

Phonegap handles this with a pause event.

document.addEventListener("pause", yourCallbackFunction, false);

Phonegap handles this with a resume event.

document.addEventListener("resume", yourCallbackFunction, false);

There are few other phonegap and jQM events and you can find them in links mentioned above.

Something you should not use in jQM app:

$(document).ready(function(){

});

The first thing you learn in jQuery is to call code inside the $(document).ready() function so everything will execute as soon as the DOM is loaded. However, in jQuery Mobile, Ajax is used to load the contents of each page into the DOM as you navigate, and the DOM ready handler only executes for the first page. To execute code whenever a new page is loaded and created, you can bind to the pageinit event. This event is explained in detail at the bottom of this page.

@Gajotres its a good one. Thank You

javascript - jQuery Mobile : What is the order of page events triggeri...

javascript jquery events jquery-mobile cordova
Rectangle 27 12

From the jQuery Mobile documentation (which is always a good place to start):

Triggered on the page being shown, after its transition completes.

Triggered on the page being hidden, after its transition completes.

I've already tried that. Check my edit, but that happens before the page html is put.

Same problem here, need to do some recalculations on pageload. Pageshow triggers after trransition before the load.

jQuery Mobile after page is shown event - Stack Overflow

jquery jquery-mobile
Rectangle 27 2

The selector for pagecontainershow should be :mobile-pagecontainer. If that does not work for you, you can use $("body") as in 1.4 the body is always the page container:

$(":mobile-pagecontainer" ).on( "pagecontainershow", function( event, ui ) {
  alert( "This page was just hidden: " + ui.prevPage );
  alert( "The current page is : $(":mobile-pagecontainer" ).pagecontainer( "getActivePage" ));
});

The second parameter of the event (ui in the example above) gives you the page you are coming from. To get the current page you can use $(":mobile-pagecontainer" ).pagecontainer( "getActivePage" ).

So you can look at the current page ID to decide what code should be run.

pageshow vs pagecontainershow in jQuery mobile 1.4 - Stack Overflow

jquery-mobile
Rectangle 27 1

you can use this snippet to check if page comes from bfcache (back-forward cache)

window.addEventListener('pageshow', function(event) {
    console.log(event);
    if (event.persisted) {
        // comes from cache
    }
});

jquery - How to handle ready and pageshow events across all browsers, ...

jquery cross-browser browser-cache
Rectangle 27 6

As many people suggested using a deferred is an okay option as long as you don't care what order deviceready and mobileinit happe in. But in my case, I needed a few pageshow events when the application first loaded and mobileinit and by extension those pageshow/pagebeforeshow/etc events were all firing before deviceready finished, so I couldn't bind to them properly using a deferred on them. This race condition was not a good thing.

What I needed to do was make sure 'mobileinit' didn't take place until after 'deviceready' was already fired. Because mobileinit fires immediately when you load JQM I chose to use jQuery.getScript to load it AFTER deviceready was already finished.

<script src="cordova-2.2.0.js"></script>
<script src="js/jquery-1.8.2.min.js"></script>
<script src="js/async.min.js"></script>
<script src="js/app.js"></script>
<script>
  document.addEventListener(
    'deviceready',
    function () {
      $('body').css('visibility', 'hidden');
      $(document).one("mobileinit", function () {
        app.init();
        $('body').css('visibility', '');
      });
      $.getScript('js/jquery.mobile-1.2.0.min.js');
    },
    false
  );
</script>

The reason I'm hiding the body is that a side effect of this method is a half second of visibility of the original HTML document before jquery.mobile loads. In this case hiding it an extra half second of empty space is preferred to seeing the unstyled document.

+1 on your answer for it inspired me to solve my problem with some slight change. First, move body.hide() code to very first line of onBodyLoad(); Second, move body.show() code to be after getScript( jQM_PATH); Because, mobileInit() is called on each JQM page transition. Not ideal. Hope this helps others.

Can you just include the rest of your index.html

This did not work for me because cordova was removing all files there weren't included using the <script> tag.

Correct way of using JQuery-Mobile/Phonegap together? - Stack Overflow

jquery jquery-mobile cordova
Rectangle 27 6

As many people suggested using a deferred is an okay option as long as you don't care what order deviceready and mobileinit happe in. But in my case, I needed a few pageshow events when the application first loaded and mobileinit and by extension those pageshow/pagebeforeshow/etc events were all firing before deviceready finished, so I couldn't bind to them properly using a deferred on them. This race condition was not a good thing.

What I needed to do was make sure 'mobileinit' didn't take place until after 'deviceready' was already fired. Because mobileinit fires immediately when you load JQM I chose to use jQuery.getScript to load it AFTER deviceready was already finished.

<script src="cordova-2.2.0.js"></script>
<script src="js/jquery-1.8.2.min.js"></script>
<script src="js/async.min.js"></script>
<script src="js/app.js"></script>
<script>
  document.addEventListener(
    'deviceready',
    function () {
      $('body').css('visibility', 'hidden');
      $(document).one("mobileinit", function () {
        app.init();
        $('body').css('visibility', '');
      });
      $.getScript('js/jquery.mobile-1.2.0.min.js');
    },
    false
  );
</script>

The reason I'm hiding the body is that a side effect of this method is a half second of visibility of the original HTML document before jquery.mobile loads. In this case hiding it an extra half second of empty space is preferred to seeing the unstyled document.

+1 on your answer for it inspired me to solve my problem with some slight change. First, move body.hide() code to very first line of onBodyLoad(); Second, move body.show() code to be after getScript( jQM_PATH); Because, mobileInit() is called on each JQM page transition. Not ideal. Hope this helps others.

Can you just include the rest of your index.html

This did not work for me because cordova was removing all files there weren't included using the <script> tag.

Correct way of using JQuery-Mobile/Phonegap together? - Stack Overflow

jquery jquery-mobile cordova
Rectangle 27 2

and change your page2.html as below

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> 
<title>Page 1</title>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.0/jquery.mobile-1.3.0.min.css" />
<script src="http://code.jquery.com/jquery-1.8.2.min.js"></script>
<script src="http://code.jquery.com/mobile/1.3.0/jquery.mobile-1.3.0.min.js"></script>
</head>
<body>
    <div data-role="page" id="page2" data-dom-cache="true">
        <div data-role="header"></div>
            <div data-role="content">
                <div data-role="collapsible-set" data-theme="c" data-content-theme="d">
                    <div data-role="collapsible">
                        <h3>Page 2</h3>
                        <p>
                            <a href="page3.html" data-transition="slide">I'm the
                                collapsible content for section 1</a>
                        </p>
                    </div>
                    <div data-role="collapsible">
                        <h3>Section 2</h3>
                        <p>I'm the collapsible content for section 2</p>
                    </div>
                    <div data-role="collapsible">
                        <h3>Section 3</h3>
                        <p>I'm the collapsible content for section 3</p>
                    </div>
                </div>
            </div>
            <div data-role="footer"></div>
        </div>
<script type="text/javascript">
$('#page2').on('pageshow',function(event){
    alert('page2 loaded');
});
</script>
</body>
</html>

It should work now. Please tell me what happens. I wrapped the script inside $('#page2').on('pageshow',function(event){});. That's the only change I've done.

check the updated code. I've assinged the swipe event to the page's ID.

Mayu Thanks for your finally found it the site was using older version JQM thanks for your time.

Jquery Mobile navigation page refresh css removed - Stack Overflow

jquery-mobile
Rectangle 27 7

<head>
<title>Index Page</title>

<!-- Adding viewport -->
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no">

<!-- Adding jQuery scripts -->
<script type="text/javascript" src="jquery/jquery-1.7.1.min.js"></script>

<!-- Since jQuery Mobile relies on jQuery core's $.ajax() functionality,
 $.support.cors & $.mobile.allowCrossDomainPages must be set to true to tell
 $.ajax to load cross-domain pages. -->
<script type="text/javascript">
    $(document).bind("mobileinit", function() {
        $.support.cors = true;
        $.mobile.allowCrossDomainPages = true;
    });
</script>

<!-- Adding Phonegap scripts -->
<script type="text/javascript" charset="utf-8"
    src="cordova/cordova-1.8.0.js"></script>

<!-- Adding jQuery mobile scripts & CSS -->
<link rel="stylesheet" href="jquerymobile/jquery.mobile-1.1.0.min.css" />
<script type="text/javascript"
    src="jquerymobile/jquery.mobile-1.1.0.min.js"></script>

</head>
<script type="text/javascript">
    // Listener that will invoke the onDeviceReady() function as soon as phonegap has loaded properly
    document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
        navigator.splashscreen.hide();

        document.addEventListener("backbutton", onBackClickEvent, false); // Adding the back button listener    

    }
    </script>
<body>
<div data-role="page" id="something" data-ajax="false">
        <script type="text/javascript">
            $("#something").on("pageinit", function(e) {

            });

            $("#something").on("pageshow", function(e) {

            });

            $("#something").on("pagebeforeshow", function(e) {

            });
        </script>

        <div data-role="header">            
        </div>

        <div data-role="content">           
        </div>      
    </div>
</body>

Correct way of using JQuery-Mobile/Phonegap together? - Stack Overflow

jquery jquery-mobile cordova
Rectangle 27 7

<head>
<title>Index Page</title>

<!-- Adding viewport -->
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no">

<!-- Adding jQuery scripts -->
<script type="text/javascript" src="jquery/jquery-1.7.1.min.js"></script>

<!-- Since jQuery Mobile relies on jQuery core's $.ajax() functionality,
 $.support.cors & $.mobile.allowCrossDomainPages must be set to true to tell
 $.ajax to load cross-domain pages. -->
<script type="text/javascript">
    $(document).bind("mobileinit", function() {
        $.support.cors = true;
        $.mobile.allowCrossDomainPages = true;
    });
</script>

<!-- Adding Phonegap scripts -->
<script type="text/javascript" charset="utf-8"
    src="cordova/cordova-1.8.0.js"></script>

<!-- Adding jQuery mobile scripts & CSS -->
<link rel="stylesheet" href="jquerymobile/jquery.mobile-1.1.0.min.css" />
<script type="text/javascript"
    src="jquerymobile/jquery.mobile-1.1.0.min.js"></script>

</head>
<script type="text/javascript">
    // Listener that will invoke the onDeviceReady() function as soon as phonegap has loaded properly
    document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
        navigator.splashscreen.hide();

        document.addEventListener("backbutton", onBackClickEvent, false); // Adding the back button listener    

    }
    </script>
<body>
<div data-role="page" id="something" data-ajax="false">
        <script type="text/javascript">
            $("#something").on("pageinit", function(e) {

            });

            $("#something").on("pageshow", function(e) {

            });

            $("#something").on("pagebeforeshow", function(e) {

            });
        </script>

        <div data-role="header">            
        </div>

        <div data-role="content">           
        </div>      
    </div>
</body>

Correct way of using JQuery-Mobile/Phonegap together? - Stack Overflow

jquery jquery-mobile cordova