🚀 UllrichLumina

jQuery Mobile document ready vs page events

jQuery Mobile document ready vs page events

📅 | 📂 Category: Javascript

When developing dynamic web applications with jQuery Mobile, understanding the intricacies of event handling is crucial. Two primary methods for executing JavaScript code are using the $(document).ready() function and leveraging jQuery Mobile’s page events. While both aim to initialize functionality, they operate differently and are suited for distinct scenarios within the framework’s single-page application model. Choosing the right approach significantly impacts application performance, user experience, and code maintainability. This comprehensive guide explores the nuances of jQuery Mobile: document ready vs. page events, providing developers with the knowledge to make informed decisions and optimize their mobile web projects. We will delve into their functionalities, explore use cases, and highlight best practices to ensure robust and efficient mobile web applications. Understanding these concepts thoroughly will enable you to build responsive and engaging experiences for your users.

Understanding $(document).ready() in jQuery Mobile

The $(document).ready() function in jQuery is a cornerstone of web development. It ensures that JavaScript code executes only after the entire HTML Document Object Model (DOM) is fully loaded. This prevents errors that can occur when attempting to manipulate elements that haven’t yet been rendered. In traditional web development, where each user action triggers a full page reload, $(document).ready() provides a reliable mechanism for initializing scripts and attaching event handlers. However, jQuery Mobile’s single-page application (SPA) architecture introduces complexities that necessitate a deeper understanding of how $(document).ready() interacts with the framework’s behavior.

In a jQuery Mobile application, $(document).ready() typically executes only once, upon the initial loading of the application’s HTML file. Subsequent “page transitions” within the application don’t trigger a full page reload, meaning $(document).ready() won’t be called again. This can lead to issues if you rely on it to initialize components or bind events that are specific to dynamically loaded page content. For instance, if you have custom widgets or elements that are injected into the DOM after the initial page load, the $(document).ready() function may not be able to properly initialize them, resulting in unexpected behavior or errors. Therefore, alternative mechanisms, such as jQuery Mobile’s page events, are required to manage event handling for dynamically loaded content.

While $(document).ready() might seem less relevant in jQuery Mobile, it still holds value for tasks that need to be performed only once during the application’s lifespan. Examples include setting up global configurations, initializing plugins that are used across all pages, or binding events to elements that are present in the initial HTML structure and persist throughout the application’s lifecycle. However, for most page-specific initialization tasks, jQuery Mobile’s page events offer a more appropriate and reliable solution. For example, setting up the initial configuration of the application or initializing a global variable, such as an API key, are suitable uses. Correctly understanding event handling is crucial for creating smooth user experiences in mobile applications.

Leveraging jQuery Mobile Page Events

jQuery Mobile provides a suite of page events specifically designed to handle the dynamic nature of its single-page application architecture. These events are triggered at various stages of the page lifecycle, providing developers with granular control over when and how their code executes. Understanding and utilizing these events is crucial for building robust and maintainable jQuery Mobile applications. Some of the most commonly used page events include pagebeforecreate, pagecreate, pageinit, pagebeforeshow, pageshow, pagebeforehide, and pagehide. Each event serves a unique purpose and is triggered at a specific point in the page transition process.

The pagecreate event, for example, is triggered after the page has been created but before it is enhanced by jQuery Mobile’s widgets. This is an ideal time to perform initial DOM manipulations or set up event listeners for elements within the page. The pageinit event, on the other hand, is triggered after the page has been fully enhanced, making it suitable for initializing widgets and performing any final setup tasks. The pageshow event is triggered when the page is visible and ready for user interaction, while the pagehide event is triggered when the page is about to be hidden. These show and hide events are excellent for managing resources and ensuring smooth transitions between pages.

Using page events ensures that your code executes at the correct time during the page lifecycle, preventing common issues such as widgets not being properly initialized or event listeners not being attached to dynamically loaded elements. Page events also provide a more organized and maintainable way to structure your code, as you can clearly define which tasks should be performed at each stage of the page transition process. According to a study by Forrester, mobile users expect applications to be responsive and load quickly. Forrester Research highlights the importance of optimizing mobile app performance. By leveraging jQuery Mobile’s page events effectively, developers can ensure that their applications meet these expectations and provide a seamless user experience. Consider this example: attaching a click event to a button that only exists after the page has been loaded. Using pageinit guarantees the button is available.

Choosing Between $(document).ready() and Page Events

The decision of whether to use $(document).ready() or jQuery Mobile’s page events hinges on the specific requirements of your application and the nature of the code you’re trying to execute. As a general rule of thumb, $(document).ready() should be reserved for tasks that need to be performed only once during the application’s initial load, while page events should be used for anything related to individual pages and their lifecycle. Understanding the scope and timing of each approach is crucial for preventing common pitfalls and ensuring optimal performance. For instance, repeatedly initializing the same plugin within a page event can lead to memory leaks and performance degradation.

When working with dynamically loaded content, page events are almost always the preferred choice. They ensure that your code executes at the right time, regardless of how the content is loaded into the DOM. If you’re initializing widgets, binding event listeners to elements that are dynamically added to the page, or performing any other tasks that are specific to a particular page, page events provide a reliable and maintainable solution. Conversely, if you have global settings or configurations that need to be set up only once when the application first loads, $(document).ready() can be a suitable option. However, even in these cases, it’s often beneficial to consider using page events to ensure consistency and avoid potential conflicts with jQuery Mobile’s internal mechanisms. Remember, jQuery Mobile’s primary design is for single page applications.

Here’s a featured snippet-optimized paragraph: jQuery Mobile page events are generally preferred over $(document).ready() for most tasks in jQuery Mobile applications. This is because page events are triggered at various stages of the page lifecycle, ensuring that your code executes at the correct time, especially when dealing with dynamically loaded content. Using page events prevents common issues such as widgets not being properly initialized or event listeners not being attached to dynamically added elements. Choose page events for page-specific initialization and event handling, and reserve $(document).ready() for tasks that only need to run once on application load.

Best Practices and Common Pitfalls

To effectively utilize jQuery Mobile: document ready vs. page events, adhere to best practices and avoid common pitfalls. One key practice is to always scope your event handlers to the specific page you’re working with. This prevents event listeners from being inadvertently attached to elements on other pages, which can lead to unexpected behavior and performance issues. Use the $(document).on() method with a selector that targets elements within the current page’s DOM structure. This ensures that the event handler is only triggered for elements within the intended page.

Another common pitfall is forgetting to unbind event listeners when a page is hidden. If you attach event listeners within a pageshow event, you should also unbind them within a pagehide event to prevent memory leaks and ensure that the event listeners are not inadvertently triggered when the page is no longer visible. Use the $(document).off() method to unbind event listeners. Additionally, avoid performing computationally intensive tasks within page events, as this can negatively impact the application’s performance and responsiveness. Defer these tasks to background processes or web workers to ensure a smooth user experience. According to Google’s PageSpeed Insights, optimizing JavaScript execution time is crucial for improving website performance. Google PageSpeed Insights offers recommendations for improving page load times.

Here’s a list of best practices:

  • Scope event handlers to the current page.
  • Unbind event listeners when a page is hidden.
  • Avoid computationally intensive tasks within page events.

And some common pitfalls to avoid:

  • Attaching event listeners globally without scoping them to a specific page.
  • Forgetting to unbind event listeners, leading to memory leaks.
  • Performing computationally intensive tasks within page events, impacting performance.
  1. Identify tasks for initial app load ($(document).ready()).
  2. Determine page-specific actions needing event handling.
  3. Use page events (pageinit, pageshow, etc.) for page-specific logic.
  4. Scope and unbind event listeners appropriately.
  5. Optimize performance to avoid lag during transitions.
Infographic here
FAQ ---
When should I use `$(document).ready()` in jQuery Mobile?
Use it for tasks that only need to run once when the application initially loads, such as setting up global configurations or initializing plugins used across all pages.
What are jQuery Mobile page events?
These are events triggered at different stages of a page's lifecycle in jQuery Mobile, like `pagecreate`, `pageinit`, `pageshow`, and `pagehide`. They are used to handle dynamic content and ensure code executes at the correct time.
Why are page events preferred for most tasks in jQuery Mobile?
Because jQuery Mobile is a single-page application framework, content is loaded dynamically. Page events ensure that JavaScript code executes at the right time during the page lifecycle, especially for dynamically loaded content.
How can I prevent memory leaks when using page events?
Unbind event listeners within the `pagehide` event using `$(document).off()` to prevent event listeners from being inadvertently triggered when the page is no longer visible.
Understanding the subtle differences between **jQuery Mobile: document ready vs. page events** is paramount for building robust, performant, and maintainable mobile web applications. While `$(document).ready()` has its place for one-time initialization tasks, jQuery Mobile's page events offer a more granular and reliable approach to handling events within the framework's single-page application model. By leveraging these events effectively, developers can ensure that their code executes at the correct time, preventing common pitfalls and optimizing the user experience. Embrace the power of page events, and you'll be well on your way to creating exceptional mobile web experiences. Are you ready to take your jQuery Mobile development skills to the next level? Explore related topics such as custom event handling and advanced widget development to further enhance your expertise. **Question & Answer :** I am using jQuery Mobile, and I am having trouble understanding differences between classic document ready and jQuery Mobile page events.
  1. What is the real difference?

    Why should

    <!-- language: lang-js --> $(document).ready() { }); 
    

    be better than

    $(document).on('pageinit') { }); 
    
  2. What is the order of page events, when you transition from one page to another?

  3. How can I send data from one page to another and is it possible to access data from previous page?

jQuery Mobile 1.4 Update:

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.

Older content:

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

$(document).on('pageinit') vs $(document).ready()

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.

Classic jQuery syntax:

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

Here’s a working example: http://jsfiddle.net/Gajotres/Q3Usv/ to demonstrate this problem.

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 }); 

Page events transition order

First all events can be found here: http://api.jquerymobile.com/category/events/

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 A - event pageremove
  6. page A - event pagehide
  7. page B - event pagebeforeshow
  8. page B - event pageshow

For better page events understanding read this:

  • 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

Page loading jsFiddle example: http://jsfiddle.net/Gajotres/QGnft/

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

Prevent page transition

If for some reason page transition needs to be prevented on some condition it can be done with this code:

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

Prevent multiple event binding/triggering

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:

$(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. Test it by moving from page 1 to page 2 and back several times. There are few ways to prevent this problem:

Solution 1

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.

Working jsFiddle example: http://jsfiddle.net/Gajotres/AAFH8/

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

Solution 2

Remove event before you bind it:

$(document).on('pagebeforeshow', '#index', function(){ $(document).off('click', '#test-button').on('click', '#test-button',function(e) { alert('Button click'); }); }); 

Working jsFiddle example: http://jsfiddle.net/Gajotres/K8YmG/

Solution 3

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 4

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

pageChange event quirks - triggering twice

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.

Example:

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

To fix this problem use any page event listed in Page events transition order.

Page Change Times

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:

  • A page change process is begun
  • A new page is loaded
  • The content for that page is “enhanced” (styled)
  • A transition (slide/pop/etc) from the existing page to the new page occurs

This is a average page transition benchmark:

Page load and processing: 3 ms

Page enhance: 45 ms

Transition: 604 ms

Total time: 670 ms

*These values are in milliseconds.

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

Data/Parameters manipulation between page transitions

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

Reference: https://stackoverflow.com/a/13932240/1848600

Solution 1:

You can pass values with changePage:

$.mobile.changePage('page2.html', { dataUrl : "page2.html?paremeter=123", data : { 'paremeter' : '123' }, reloadPage : true, changeHash : true }); 

And read them like this:

$(document).on('pagebeforeshow', "#index", function (event, data) { var parameters = $(this).data("url").split("?")[1];; parameter = parameters.replace("parameter=",""); alert(parameter); }); 

Example:

index.html

```

First Page

```
**second.html**
```

Second Page

```
**Solution 2:**

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 : '' } 

Example: http://jsfiddle.net/Gajotres/9KKbx/

Solution 3:

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.

Solution 4:

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"; } 

Example: http://jsfiddle.net/Gajotres/J9NTr/

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

Don’t Use .live() / .bind() / .delegate()

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.

Benchmarking:

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

Final notes

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.

Changes:

  • 30.01.2013 - Added a new method of multiple event triggering prevention
  • 31.01.2013 - Added a better clarification for chapter Data/Parameters manipulation between page transitions
  • 03.02.2013 - Added new content/examples to the chapter Data/Parameters manipulation between page transitions
  • 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