3

In my Site, am seeing pageinit being called during browser's forward button selection. Is this correct. Will this not bind the registered events twice.

First.html

<!DOCTYPE HTML>
<html>
    
    <head>
        <title>Test1</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.css" />
        <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
        <script src="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.js"></script>
        <script src="../scripts/common.js"></script>
    </head>
    
    <body>
        <div data-role="page" id="first">
             <h1 style="background: red">Swipe 1</h1>
         <a href="second.html">Click</a>
        </div>
    </body>

</html>

Second.html

<!DOCTYPE html>
<html>

    <head>
        <title>Test2</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.css" />
        <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
        <script src="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.js"></script>
        <script src="../scripts/common.js"></script>
    </head>

    <body>
        <div data-role="page" id="second">
            <div data-role="header">
                <h1>jQuery Mobile</h1>
            </div>
            <div data-role="content">   
              <a href="third.html">Click</a>
            </div>
            <div data-role="footer">
                <h4>www.jboss.org/developer</h4>
            </div>
        </div>
    </body>

</html>

third.html

<!DOCTYPE html>
<html>

    <head>
        <title>jQuery Mobile Template</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" />
        <script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
        <script type="text/javascript" src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script>
    </head>

    <body>
        <div data-role="page" id="third">
            <div data-role="header">
                    <h1>jQuery Mobile</h1> 
            </div>
            <div data-role="content">
                <ul id="listOfItems" data-role="listview" data-inset="true" data-filter="true">
                    <li><a href="">One</a>
                    </li>
                    <li><a href="">Two</a>
                    </li>
                    <li><a href="">Three</a>
                    </li>
                </ul>
            </div>
            <div data-role="footer">
                <h4>www.jboss.org/developer</h4> 
            </div>
        </div>
    </body>

</html>

common.js

$(document).on('pageinit', "#first", function (event) {
    console.log("first");
});


$(document).on('pageinit', "#second", function (event) {
    console.log("second");
});


$(document).on('pageinit', "#third", function (event) {
    console.log("third");
});

Can you check the above code and let me know why pageinit is called everytime.

Serge P
  • 1,173
  • 3
  • 25
  • 39
user694688
  • 593
  • 1
  • 15
  • 32
  • Can you please describe your question with more details? Currently it is very confusing. – Gajotres Jun 05 '13 at 11:24
  • Say there are three pages: A, B and C. I navigate from A to B and then to C. If i come back from page C to B and then navigate to C again using the forward button in the browser, am seeing the pageinit being called again for Page C. Is it correct. – user694688 Jun 05 '13 at 11:40
  • This should not be possible unless you are not using ajax for page loading. Pageinit should trigger only once. – Gajotres Jun 05 '13 at 12:00
  • If possible can you put your HTML here? I will check your code. – Gajotres Jun 05 '13 at 12:33
  • Have added my code. Pls check. – user694688 Jun 05 '13 at 14:41
  • Let me just confirm you that I have just recreated your problem and I am looking into it. – Gajotres Jun 05 '13 at 15:03
  • Happy that you could reproduce the issue. – user694688 Jun 05 '13 at 15:48
  • Gajotres- Please clarify on my queries. This again goes back to the discussion on pageinit vs pageshow. Ideally , a page should not be reloaded when we press the back or forward button. Isnt it. – user694688 Jun 05 '13 at 19:14
  • Gajotres- Can you throw some light on this. What is the approach that i should take now. Should i use dom caching. If i do not use, then page will reload even for forward/back button press. Am also worried why all this is not documented properly in JQM docs. – user694688 Jun 06 '13 at 10:22
  • I am going to write an answer in next few hours, first I want to gen a response from jQuery Mobile developers regarding this question. – Gajotres Jun 06 '13 at 10:24
  • Awaiting for your answer mate... – user694688 Jun 07 '13 at 07:15
  • Just got everything to write you an answer. – Gajotres Jun 07 '13 at 07:32
  • I hope you will be satisfied with my answer. Feel free to ask more questions. – Gajotres Jun 07 '13 at 14:05

2 Answers2

5

Intro

Before we can talk about page events we need to talk about jQuery Mobile page architecture. jQuery Mobile applications can be created in two different ways, multi-page template or several HTML pages.

Different jQuery Mobile page architectures

Multi-page template

In this kind of template everything is loaded into the DOM. No matter how many times user transitions from one page to another previous page will stay loaded into the DOM. While this is the best solution for smooth transition between pages it can burden the DOM. This is usually not a problem on desktop browsers but mobile browsers can suffer, particularly on a low end devices.

Multi HTML template

This template solution requires several HTML pages. It is an excellent option for large mobile app construction but there's a catch. Unlike multi-page template each time page is visited it will loaded into the DOM. On slower devices it can cause transition problems particularly if destination page is a large one. This can be solved with page prefetching where jQuery Mobile loads the target page in the background after the primary page has loaded and the pagecreate event has triggered. BUT there's another large problem and this is not sufficiently described in jQuery Mobile documentation. During the page transition previous page is going to be removed from the DOM. This is done to prevent content accumulation inside the DOM. This can also be prevented with another attribute called:

data-dom-cache="true"

or by initializing global parameter:

$.mobile.page.prototype.options.domCache = true;

How page architecture impacts page events

jQuery Mobile has several page events (more about it can be found HERE or HERE). They are here to cover full page load / transition process. Advanced jQuery Mobile users know to use pageinit event instead of jQuery classic document ready event. Just like document ready, pageinit is here to trigger only once during the page initialization.

But there's a catch, pageinit will trigger only once during the page initialization inside the DOM. If page is removed from the DOM (in multi HTML template) and loaded again pageinit will trigger again.

In a nutshell each page DOM initialization will trigger new page events initialization. Like mentioned previously this can be prevented with page cashing.

Impact of page cashing

This is almost a tabu theme for jQuery Mobile developers so let me tell something, there's no need to be afraid of page cashing. Believe me, jQuery Mobile is robust framework and it usually plays well on every available platform. Huge number of complains related to jQuery Mobile are not directly related to its large DOM size requirements so don't worry about cashing.

That doesn't mean you should fill the DOM like a drunken sailor. Every app development must be planed in advance. Mostly used pages must permanently stay inside the DOM. Everything else should be used ad hoc (loaded / removed when needed).

Community
  • 1
  • 1
Gajotres
  • 57,309
  • 16
  • 102
  • 130
  • Well, our answers do not differ.. However the phrase "During the page transition previous page is going to be removed from the DOM" is not actually true. It is true for all the pages except the first page. The first page is cached in DOM even if domCache is disabled. – Apostolos Emmanouilidis Jun 07 '13 at 15:26
  • Gajotres- Thanks again. 1. The problem is that if we do not use dom caching, we will load the data again from server even for back and forward button press, which is not the intended behaviour. I think if we do not use JQM, browser will take from cache rather than downloading the data again. Is it not? 2. If we use domcache as true, when will the data change again. Will it not change at all. 3.Can you also explain the multiple binding problem because of this and the correct solution for this. – user694688 Jun 08 '13 at 05:59
  • Gajotres- Can you pls answer the above question. – user694688 Jun 11 '13 at 08:34
  • @user694688 if you use `data-cache` is enabled, you need to force remove old pages/contents and load fresh data from server. – Omar Jun 21 '13 at 16:25
2

EDITED:
It seems that when using a multipage template approach (single html with all pages included) then pageinit is fired once since the pages are loaded in DOM and remain there when transitioning between pages.

However when using multiple pages and navigating though Ajax you will notice that the pages contain an attribute data-external-page="true" except the first page. The first page is always cached in DOM even if you're using domCache false. But the pages except the first page are loaded and cleaned out after you leave them. That's why pageinit is fired on back/forward button clicks.

The domCache sets whether to keep the page in the DOM after the user has navigated away from it. You can read about it on jQM docs. By default the domCache option's value is false.

Adding:

$(document).on('mobileinit', function () {
    $.mobile.page.prototype.options.domCache = true;
});

between jQuery js and jQuery Mobile js will cause the pages to be cache in DOM. Therefore pageinit will not fire.

An alternative is to add data-dom-cache="true" on your anchor.

The drawback of using domCache is that the DOM can be large, resulting in memory issues. In a such approach the DOM management is left on the developer.

At last make sure that you're using the same jQ, jQM versions in your pages. The first 2 pages are using jQ 1.9.1, jQm 1.3.1 and the third page is using jQ 1.7.1, jQM 1.1.0. This is irrelevant with the specific issue but it worth to mention it.

I hope this helps.

Apostolos Emmanouilidis
  • 7,179
  • 1
  • 24
  • 35
  • Thanks. is there any drawback in setting the domCache option to true. Would like to know why the default status is false. And, i was doing the following things in pageinit: 1. Loading the page data using ajax. 2. Registering the events for the page. So, if i make domcache as true, then pageinit will not be called on navigation. And, the data will not change at all. Should i move the loading of data to pageshow then. The problem then will be pageshow will load data again even on back button press. It has become even more confusing now. – user694688 Jun 05 '13 at 18:12
  • Looking for more clarification on the above answer. – user694688 Jun 05 '13 at 19:17
  • Pageshow will be fired even if domCache is true. I would not use the global domCache option but the corresponding anchor attribute.The drawback is that the DOM can be large, resulting in memory issues. That's why JQM has disabled this option by default. – Apostolos Emmanouilidis Jun 05 '13 at 19:19
  • Say, if am not adding domCaching at all, then there are two things: 1. pageinit will be called during navigation multiple times and the events are going to be bind multiple times. 2. The state of the page is going to change. Say, if there are three tabs. am navigating to another page when i am in the third tab. When coming back, pageinit is going to be called again, which will load the first tab. Actually, it should be in the third tab. And, unnecessarily we are going to load the data from server- if we load data in pageinit or pageshow. – user694688 Jun 05 '13 at 19:31
  • I've updated my answer. You're facing this issue because when using a multiple page approach, the page is removed from DOM after you leave it (even if when using Ajax). I hope I threw some light.. – Apostolos Emmanouilidis Jun 05 '13 at 20:35