jQuery Mobile “Page” Events – What, Why, Where, When & How?


More events: Page Container Load Events.

“Not bad” news: Two plugins that may be of help (Link)

Happy news: jQuery Mobile team is sparing a surprise for us on jQM 1.4.3 release! (Link)

We all know that jQuery-Core requires .ready() to initialize any code uses jQuery. However, it might malfunction when used in jQuery-Mobile, especially when Ajax is enabled. Why? .ready() fires once per document / file, where jQuery-Mobile’s Page Events fire continuously. I don’t want to go deeply into details and lengthy comparisons, let’s just focus on jQuery-Mobile’s Page Events.

Why jQuery-Mobile’s Page Events?

If you want to have superior control over your webapp, you first need to know their occurrence, sequence, usage and whether they can be delegated. Moreover, you need to differentiate between the ones that fire once per document, once per page and fire continuously. Once you understand the aforementioned bla bla bla, you will probably fall in love with those events.

Page Events Sequence

Multi-Page Model

Multi-Page Model

Single Page Model

Single Page Model

Page Events Usage

mobileinit

Occurrence: Once per “Document-Framework”
Delegate-able: No

The very first event that fires – even before .ready() – is mobileinit, it fires after loading jQuery-Core and before loading jQuery-Mobile. This event is used to override default settings of jQuery-Mobile, aka Global Settings (Defaults).

For example, if you want to add “back button” to each and every page, instead of statically adding data-add-back-btn="true" to each “Header”, all you need is to add the below line.

<script src="jquery.js"></script>
<script>
  $( document ).on( "mobileinit" , function () {
    $.mobile.toolbar.prototype.options.addBackBtn = true;
  });
</script>
<script src="jquerymobile.js"></script>

 

pagebeforechange and pagecontainerbeforetransition

Occurrence: On Navigating
Delegate-able: No

These two events do the same job, both omit ui.toPage and ui.options of current page and next page. They continuously whenever a user navigates from page to another, once per current and once per page to be moved to. Note that pagebeforechange fires twice in jQuery-Mobile 1.4, however, as of jQuery-Mobile 1.5 the second call will be removed as it is replaced with pagecontainerbeforechange.

How to utilize them? At this stage and before pagecontainerbeforeshow fires, you can redirect user to any other page than the one a user intends to navigate to. For example, a user wants to navigate from “pageX” to “pageY”, but he/she has no access to “pageY”! Use any of those events to navigate to “pageZ” without passing through “pageY”. If you use any other event, e.g. pagecontainerbeforeshow or pagecontainershow, “pageY” will be visible for milliseconds before moving to “pageZ”.

Note: I have posted a new article of how to use pagecontainerbeforechange / pagebeforechange.

Demo

$( document ).on( "pagebeforechange" , function(e, data) {
  var toPage = data.toPage[0].id;
  if(toPage == "pageY" && !userLogged) {
    $.mobile.pageContainer.pagecontainer("change", "#pageZ");
  }
});

 

pagebeforecreate

Occurrence: Once per “New Page”
Delegate-able: Yes

A page and all widgets within it are auto-initialized after the occurrence of this event. It is best used to add elements dynamically without the need to call any enhancement function, as they will be auto-initialized.

Demo

$( document ).on( "pagebeforecreate", "#pageX", function(event) {
  $( this ).append( "<elements> </elements>" )
});

 

pagecreate

Occurrence: Once per “New Page”
Delegate-able: Yes

In short, you can call it “.ready()” of jQuery-Mobile. It is a multi-purpose event that can be used for almost everything. The most important part about it is, it can be delegated; in other words, it can be attached to a specific pages(s).

To add listeners without duplicating/multiplying them (e.g. click, tap, swipe…etc.) should be during this event. It can be also used to add elements dynamically to a specific page(s), however, these elements will require manual initialization.

Third party plugins that don’t require visual appearance or space among other contents, can also be initialized during this event, e.g. jQuery-validate. Other plugins which need to be displayed, might “malfunction” if initialized at this point, since they require space to work with. They might not work properly because the target page is still hidden and its’ dimensions are still unset. For example Google Maps, iDangerous Swiper and any other plugin images gallery plugin.
Demo

/* specific page (delegation) */
$( document ).on( "pagecreate", "#pageX", function ( event ) {
  $( ".foo" ).on( "change", function () {
    var value = $(this).val();
  });
});

/* Add header dynamically and initialize it */
$( document ).on( "pagecreate" , function ( event ) {
  $( event.target ).prepend( $('<div data-role="header"><h1>Header</h1></div>').toolbar() );
});

Note: In Single Page Model, when navigating away from a page, it gets removed from DOM. When it is visited again, it passes through both events pagebeforecreate and pagecreate. Hence, in order to avoid multiplied listeners on same element(s) previously added listeners should be removed using .off() and then re-bind listeners, or just attach them once by using .one() bound to pagecreate.

In case $.mobile.page.prototype.options.domCache = true; is used or data-dom-cache="true" is added to page div, then there is no need to remove previous listeners.

/* Single Page Model - Remove then Add listeners */
$( document ).on( "pagecreate", "#pageX", function ( event ) {
  $( ".foo" ).off( "change" ).on( "change", function () {
    var value = $(this).val();
  });
});

/* Single Page Model - Add listeners one time */
$( document ).one( "pagecreate", "#pageX", function ( event ) {
  $( ".foo" ).on( "change", function () {
    var value = $(this).val();
  });
});

 

pagecontainerbeforehide

Occurrence: On Navigating
Delegate-able: No

This event fires before hiding current page. It carries a data object ui.nextPage of the page to be shown. The data object can be used to manipulate DOM / elements of next page, or if you want to do changes on current active page, you can use pagecontainerbeforeshow‘s data object ui.prevPage.

$( document ).on( "pagecontainerbeforehide", function ( event, ui ) {
  $(".foo", ui.nextPage ).addClass( "ui-screen-hidden" ); /* hide .foo element */
});

 

pagecontainerbeforeshow

Occurrence: On Navigating
Delegate-able: No

It is similar to the previous event, except for it omits data object of current page ui.prevPage, so use it manipulate DOM / elements of current page. If you want to do changes to next page, use pagecontainerbeforehide‘s data object ui.nextPage.

$( document ).on( "pagecontainerbeforeshow", function ( event, ui ) {
  $(".foo", ui.prevPage ).val(""); /* reset value of .foo element on current page */
});

 

pagecontainertransition

Occurrence: On Navigating
Delegate-able: No

It is similar to pagecontainerbeforetransition and it omits same data objects ui.toPage and ui.options. However, it fires after transition is complete on next page and before hiding current page completely.


 

pagecontainerhide

Occurrence: On Navigating
Delegate-able: No

This event fires after current page is completely hidden. It also carries a data object ui.nextPage.

$( document ).on( "pagecontainerhide", function ( event, ui ) {
  $(".foo", ui.nextPage ).removeClass( "ui-screen-hidden" ); /* show .foo element */
});

 

pagecontainershow

Occurrence: On Navigating
Delegate-able: No

Another important event and mostly used to initialize widgets that require working place such as Google Maps and image galleries. It fires after the page is fully visible and dimensions are set. To do modifications to active page, you will need to use $.mobile.pageContainer.pagecontainer( "getActivePage" ) which returns an object of current active page.

$( document ).on( "pagecontainershow", function ( event, ui ) {
  var activePage = $.mobile.pageContainer.pagecontainer( "getActivePage" );
  $(".swiper", activePage ).swiper(); /* initialize "swiper" plugin */
});

Conclusion

Using Page Events facilitates controlling as well as manipulating your webapp. Although all events (except for one) can’t be delegated as of jQuery-Mobile 1.4, but still there are many ways to overcome this issue. There is a debate (issue #6865) regarding the new “pageContainer” events and why jQuery-Mobile team decided to deprecated previous “Page Events” and replace them with “pageContainer” events.

Buy Me A Coffee :) @ ko-fi.com

Advertisements

33 thoughts on “jQuery Mobile “Page” Events – What, Why, Where, When & How?

  1. Can anyone please help me regarding on swipe left or right, page selected and border shows on every page loads on android device.

  2. Hi Omar… Excelent post! I wanted to ask you 2 things:
    1) Is there any chance that pagecontainerbeforetransition be fired instead after pagecreate in the first page in both models?
    and
    2) also in the first page in both models, is there any chance that pagecontainershow be fired instead after pagecontainertransition?
    Thanks a lot for this great post.
    Alfredo Meraz.

  3. Thank you for this. It is soooo helpful. I just have a question. Using jQuery Mobile 1.4.5, I have a multi-page template where I am using the jQuery Validation plugin on several pages. I would like to set the defaults for this plugin at one location. Where would I put it? You mentioned “mobileinit” would not be the correct place because “mobileinit” fires before the “ready”. Also, I have several “pagecreate” but don’t want to copy the same options in all of them. So where would be a correct place to set defaults for a jQuery plugin?

  4. Hi @gianthead,

    Unfortunately, as of jQM 1.4 its not possible to delegate events to specific pages, except for “pagecreate” and “beforecreate”. Therefore, you need to check “ui.toPage” as you mentioned in your comment. It’s easier to check page’s ID, however, url works too.

    I sometimes wrap other events in “pagecontainerbeforechange” to call them one time “.one()”. It also requires checking page’s url/id, but at least, you can bind an event once.

    “pagecontainerbeforechange” and “pagecontainerbeforetransition” are really very helpful. Let me know if you need more details and/or an example. Also, feel free to visit me on freenode IRC network, details are available in “About” page.

  5. Thanks for the figure. It helps a lot.

    One thing that’s not clear to me is how can I fire an event handler only for a specific page? Lets say I attach a handler to $(document).on(“pagecontainerbeforeshow”, …), then this will trigger when I navigate to the page AND when I navigate to the next page. I suppose I could check ui.toPage.baseUri and do a string match for the page url within the handler, but is there a better way that doesn’t require me to hardcode the page url?

  6. Pingback: jQuery Mobile “Page” Events – What, Why, Where, When & How? | jQuery Mobile Tricks – Abdullah Adeɘb
  7. This post should be in the official documentation of jQuery Mobile.
    It makes a lot more sense.
    Thanks for the write up.

  8. Hi again,

    What do you mean by with anchor or without? Could you please elaborate more or provide me with a fiddle?

    Thanks 🙂

  9. Thanks for your reply. That is working great for me.

    I found there is a different sequence when the first page includes #pagename and when it doesn’t:

    when no anchor:
    pagecontainershow
    pagecontainertransition
    ready
    with anchor:
    ready
    pagecontainershow
    pagecontainertransition

    Do you know if this is the expected behaviour, or if I’ve done something weird?

  10. Can you add to the diagram when the document ready and window load events fire? I’m having an issue binding to pagecontainerbeforeshow on the initial page using $(“:mobile-pagecontainer”).on(“pagecontainerbeforeshow”, …);

    If I put that in script tags, it never fires. If I put it $(function(){…}); it fires on every page change, but not the initial page.

  11. Pingback: useful links while working with jQuery mobile | IT Technologies
  12. Pingback: jQuery Mobile Events Diagram | IT Technologies
  13. Pingback: jQuery Mobile “Page” Events – Extra | jQuery Mobile Tricks
  14. I notice you haven’t included the pagecontainerload event on this chart. Is there a reason? (I know these events are in flux and more changes are planned, not sure if this is omitted becuase it’s slated for removal?)

  15. Pingback: Page events order in jQuery Mobile - Version 1.4 update | Gajotres.net
  16. Hi again Juan,

    As far as I know, scrolling problems are noticeable in Android more than in iOS. It’s difficult to determine what’s causing the problem without seeing it in action. If you provide me with a link I’ll be look into it.

  17. Hey there 🙂 the main problem after looking for the issue is the scrolling in iOS, a previous attempt to fix it made viewport scrollable, which gave the headers the feeling the weren’t staying in a fixed position.

    That’s fixed already, however scrolling content dynamically added causes a blink when you’re about to reach at the bottom of content and some other issues that are happening when you scroll that are not present in android. Is there any known issue with iOS scrolling and jQuery Mobile?

    I’m using the latest jquery mobile version (1.4.2 minified) and jquery 2.0.3 also minified.

    Thanks for your help!

  18. Hola Juan,

    I am glad that you find this article helpful.

    Header toolbar can be fixed by adding data-position=”fixed” attribute to Header div. Could you please elaborate on your issue? Are you appending toolbars dynamically or are they static ones?

    Thank you!

  19. Hi there, this is an excellent article, after reading this I changed some of the event triggering (specially to remove pageshow calls because of his dark future 😦 ) and now most of the page creation is being made between pagecreate and pagebeforecreate.

    However there’s no way to keep headers fixed, is this a common issue?

  20. Hi Jon,

    I came out with this diagram after some experiments and reading of future updates on jQuery Monile 1.5. Please note that I have taken out `pagebeforechange` twice as it currently fires on current page (once) and next page (once). As per the team, in JQM 1.5, first call is `pagebeforechange` and second call is `pagecontainerbeforetransition` (next page). Both omit same data object with no difference.

    Schmitz has pointed out that he is working on refactoring `pageContainer` events, which should be – hopefully – released on JQM 1.4.3 stable version.

    Please let me know if you have any suggestions to improve this post.

    Thank you!

  21. Wow, this is great, thank you! I’ve been looking for a diagram like this for 1.4!

    Could you please make it clear if you don’t mind the jQuery Mobile team using or adapting this diagram? It would be a great addition to the documentation.

    Note that there is a trick I have used at pageinit that ought to work as well on the new pagecreate. You can temporarily set the page to visible by adding CSS inline. You can then do height calculations, and restore the original inline CSS before returning from the event. You might expect this would result in some “flash”, but it does not, because layout/rendering doesn’t take place until after return from the event, and the layout/rendering code never realizes that you temporarily set the page to visible.

  22. Pingback: jQuery Mobile events | koding notes

Drop me a line or two ;)

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s