C H A P T E R  27

Pages and Navigation

In this chapter, I describe one of the key building blocks for jQuery Mobile applications: pages. I touched on pages in Chapter 26, but now I'll go into the detail and show how to define, configure, and navigate between pages. Table 27-1 provides the summary for this chapter.

Image

Image

Understanding jQuery Mobile Pages

In Chapter 26, I showed you how you define jQuery Mobile pages within an HTML document using elements with specific roles. To recap, Listing 27-1 shows a simple page.

Listing 27-1. A Simple jQuery Mobile Page in an HTML Document

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="jquery.mobile-1.0.css" type="text/css" />
    <script type="text/javascript" src="jquery-1.6.4.js"></script>
    <script type="text/javascript" src="jquery.mobile-1.0.js"></script>   
</head>
<body>
    <div data-role="page">
       <div data-role="content">
           This is Jacqui's Flower Shop
       </div>
   </div>
</body>
</html>

This is a minimal page, which consists of two key elements, each of which has a data-role attribute. The element whose role is page denotes the region of the HTML content that contains the jQuery Mobile page. As I mentioned in Chapter 26, one of the key characteristics of jQuery Mobile is that the pages that are displayed to the user are not directly related to the HTML elements that contain them.

The other important element has a role of content. This denotes the part of the jQuery Mobile page that contains the page content. A page can contain different sections of which the content is only one, as I'll demonstrate shortly. You can see how the page is displayed in the browser in Figure 27-1.

Image

Figure 27-1. Displaying a minimal jQuery Mobile page in the browser

Adding Headers and Footers to a Page

In addition to a content section, a jQuery Mobile page can contain a header and a footer. These are denoted by elements whose data-role attributes are set to header and footer, respectively. Listing 27-2 shows both of these sections added to the example page.

Listing 27-2. Adding a Header and a Footer to the Example Page

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="jquery.mobile-1.0.css" type="text/css" />
    <script type="text/javascript" src="jquery-1.6.4.js"></script>
    <script type="text/javascript" src="jquery.mobile-1.0.js"></script>   
</head>
<body>
    <div data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>

        <div data-role="content">
           This is Jacqui's Flower Shop
        </div>
        <div data-role="footer">
           <h1>Home Page</h1>
        </div>

   </div>
</body>
</html>

You can see the effect of these additions in Figure 27-2. The problem with headers and footers is that they can occupy a lot of space on a small screen, as the figure shows.

Image

Figure 27-2. Adding a header and footer to the page

You will also notice that the footer is displayed at the end of the content section, rather than at the bottom of the page. You might be tempted to force the position of the footer using CSS, but mobile browsers don't always respond properly to this. Listing 27-3 shows the CSS “fix.”

Listing 27-3. Using CSS to Fix the Position of the Footer in the Page

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="jquery.mobile-1.0.css" type="text/css" />
    <script type="text/javascript" src="jquery-1.6.4.js"></script>
    <script type="text/javascript" src="jquery.mobile-1.0.js"></script>
    <style type="text/css">
        #footer {position: absolute; bottom: 0}

    </style>
</head>
<body>
    <div data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
           This is Jacqui's Flower Shop
        </div>
        <div id="footer" data-role="footer">
           <h1>Home Page</h1>
        </div>                
   </div>
</body>
</html>

The problem is that mobile browsers deal with document height inconsistently. Figure 27-3 shows what you end up with in Opera. The footer is shown as off the page. The first frame of this figure shows the initial page layout, and the second frame shows the footer when I scroll down the page.

Image

Figure 27-3. Opera Mobile displaying the page footer

You might be tempted to revisit the meta element that sets the viewport size and try to fix the height. This is an unrewarding task. The support for viewport height in mobile browsers is nonexistent as I write this. It is also a dangerous approach. You can't tell in advance how much of the screen is given over to the browser controls. This means that relying on the device height to set the viewport height doesn't solve the problem, leaving you with the option of setting the height to a set number of pixels. This is impossible to set properly given the variety of screen resolutions available in the smartphone and table markets.

Image Tip For these reasons, I tend not to use footers at all. I do use headers, because it adds a degree of consistency between the pages in my jQuery Mobile applications.

Adding Pages to a Document

You can define multiple jQuery Mobile pages in a single document. This can be useful for simple web applications because you can bundle everything you need into a single HTML file. Listing 27-4 shows a multipage document.

Listing 27-4. Defining Multiple jQuery Mobile Pages in an HTML Document

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="jquery.mobile-1.0.css" type="text/css" />
    <script type="text/javascript" src="jquery-1.6.4.js"></script>
    <script type="text/javascript" src="jquery.mobile-1.0.js"></script>
</head>
<body>
    <div id="page1" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
           This is Jacqui's Flower Shop
        </div>
    </div>    
    <div id="page2" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
           This is page 2
        </div>
   </div>

</body>
</html>

This example defines two pages in the document. I have used the id attribute to assign each page a unique identifier, and these values form the basis for navigating between pages. To let the user navigate between pages, you add an a element whose href is the id of the target page, as shown in Listing 27-5.

Listing 27-5. Navigating Between Pages

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="jquery.mobile-1.0.css" type="text/css" />
    <script type="text/javascript" src="jquery-1.6.4.js"></script>
    <script type="text/javascript" src="jquery.mobile-1.0.js"></script>
</head>
<body>
    <div id="page1" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
           This is Jacqui's Flower Shop
           <p><a href="#page2">Go to page 2</a></p>
        </div>
    </div>    
    <div id="page2" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
           This is page 2
           <p><a href="#page1">Go to page 1</a></p>
        </div>
   </div>    
</body>
</html>

In this example, I have added links between the pages. When a link is clicked, jQuery Mobile takes care of displaying the appropriate page from the document, as demonstrated in Figure 27-4.

Image

Figure 27-4. Navigating between pages in a document

Configuring Page Transitions

When the user navigates between pages, jQuery Mobile uses an animation effect to transition between one page and the next. The default effect is called slide, which has the outgoing page slide to the left while the new page slides in from the right. jQuery Mobile defines six effects, as follows:

  • slide
  • pop
  • slideup
  • slidedown
  • fade
  • flip

As I write this, the flip effect causes problems on Android devices and should be used with caution.

Image Tip The mobile browser emulators don't handle transitions very well and generally just ignore them. They work just fine on real mobile devices, however. If you want to see the transition on the desktop, then use either Google Chrome or Apple Safari, both of which handle the effects well.

You can change the way that an individual page transition is animated by using the data-transition attribute on the a element, setting the value to the effect you want. Listing 27-6 provides an example.

Image Note I can't easily show you the different animation effects using figures. This example is one that requires experimentation in the browser. You can avoid having to type in the HTML by downloading the source code that accompanies this book and that is freely available from Apress.com.

Listing 27-6. Using the data-transition Attribute

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="jquery.mobile-1.0.css" type="text/css" />
    <script type="text/javascript" src="jquery-1.6.4.js"></script>
    <script type="text/javascript" src="jquery.mobile-1.0.js"></script>
</head>
<body>
    <div id="page1" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
           This is Jacqui's Flower Shop
           <p><a href="#page2" data-transition="pop">Go to page 2</a></p>
        </div>
    </div>    
    <div id="page2" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
           This is page 2
           <p><a href="#page1">Go to page 1</a></p>
        </div>
   </div>    
</body>
</html>

When the user clicks the highlighted link, the pop transition is used to display the target page. The pop effect is applied only to that single link. Other links in the page or in other pages in the same document will continue to use the default. Set the data-transition attribute to none if you want to disable the animation effect.

Tip You can change the direction in which the effect is played by applying the data-direction attribute to the a element with a value of reverse. In the “Changing the Current Page” section, I give an example of reversing the transition direction and explain why it can be useful.

If you want to change the animation effect used for all navigation, then you need to set a global option. jQuery Mobile defines the defaultPageTransition setting, which you can set when the mobileinit event is triggered. Listing 27-7 shows how this is done.

Listing 27-7. Changing the Default Page Transition

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="jquery.mobile-1.0.css" type="text/css" />
    <script type="text/javascript" src="jquery-1.6.4.js"></script>
    <script type="text/javascript">
        $(document).bind("mobileinit", function() {
            $.mobile.defaultPageTransition = "fade"
        })
    </script>

    <script type="text/javascript" src="jquery.mobile-1.0.js"></script>    
</head>
<body>
    <div id="page1" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
           This is Jacqui's Flower Shop
           <p><a href="#page2">Go to page 2</a></p>
        </div>
    </div>    
    <div id="page2" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
           This is page 2
           <p><a href="#page1">Go to page 1</a></p>
        </div>
   </div>    
</body>
</html>

There is no convenient method for registering a handler function for the mobileinit event, so you have to select the document object and use the bind method. The arguments to this method are the name of the event you want to handle and the handler function to use when the event is triggered.

Image Caution The mobileinit event is triggered as soon as the jQuery Mobile script library is loaded, which means you have to register the handler function to change the global jQuery Mobile setting before the jQuery Mobile library is referenced in a script element. You can see how I have done this in the listing. The function will never be executed if the call to the bind method is not defined before the script element that loads the jQuery Mobile code.

To change the value of a global setting, you assign a new value to a property of the $.mobile object. Since I want to change the defaultPageTransition setting, I assign a value to the $.mobile.defaultPageTransition property, like this:

$.mobile.defaultPageTransition = "fade"

This statement sets the default effect to fade. I can still override this setting with the data-transition attribute, but the default is no longer slide.

Linking to External Pages

You don't have to include all the pages in a single document. You can add links just as you would if using regular HTML. To demonstrate this, I have created a new file called document2.html, the content of which is shown in Listing 27-8.

Listing 27-8. The Content of the document2.html File

<!DOCTYPE html>
<html>
<head>
    <title>Document 2</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="jquery.mobile-1.0.css" type="text/css" />
    <script type="text/javascript" src="jquery-1.6.4.js"></script>
    <script type="text/javascript" src="jquery.mobile-1.0.js"></script>    
</head>
<body>
    <div id="page1" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
           This is page 1 in document2.html
           <p><a href="#page2">Go to page 2 in this document</a></p>
           <p><a href="example.html">Return to example.html</a></p>
        </div>
    </div>    
    <div id="page2" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
           This is page 2 in document2.html
           <p><a href="#page1">Go to page 1</a></p>
        </div>
   </div>    
</body>
</html>

This document contains a pair of jQuery Mobile pages, following the same structure as in the other examples. Linking to pages in other documents is very simple. You just define an a element whose href attribute contains the URL of the target document, as shown in Listing 27-9.

Listing 27-9. Navigating to a Page in Another HTML Document

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="jquery.mobile-1.0.css" type="text/css" />
    <script type="text/javascript" src="jquery-1.6.4.js"></script>
    <script type="text/javascript" src="jquery.mobile-1.0.js"></script>    
</head>
<body>
    <div id="page1" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
           This is Jacqui's Flower Shop
           <p><a href="#page2">Go to page 2</a></p>
           <p><a href="document2.html">Go to document2.html</a></p>
        </div>
    </div>    
    <div id="page2" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
           This is page 2
           <p><a href="#page1">Go to page 1</a></p>
        </div>
   </div>    
</body>
</html>

jQuery Mobile uses Ajax to load the specified document and displays the first page automatically, using a transition effect if one has been specified. You can see the result in Figure 27-5.

Image

Figure 27-5. Navigating to a page in another document

Image Tip jQuery Mobile automatically applies its styles and enhancements to remote documents that are loaded via Ajax. This means you don't have to include the jQuery and jQuery Mobile script and link elements in files such as the document2.html file I used in the example. That said, I recommend you do include those references because it is possible to prevent jQuery Mobile from using Ajax when making such requests, and if this is done, then the automatic processing of content isn't performed.

Dealing with the Ajax/Page ID Issue

It isn't all plain sailing when linking to pages in other documents. There is a conflict between the way that Ajax content is managed and the way that jQuery Mobile pages are defined. Both rely on the value of the id attribute of elements. Figure 27-6 shows the problem.

Image

Figure 27-6. The multipage Ajax issue

In this figure, I click the link in example.html, which loads document2.html. I then click the link that should display the page2 element in document2.html, but what I get is actually the page2 element in example.html, a confusing an unexpected result.

You can address this in two ways. The first, and the one that I use, is to define only one jQuery Mobile page per HTML document. This is also the advice from the jQuery Mobile development team.

The second approach is to disable Ajax when loading multipage documents. This fixes the problem, but it does mean that jQuery Mobile is unable to apply a transition effect when showing the new page. You can disable Ajax for a single a element by setting the data-ajax attribute to false, as shown in Listing 27-10.

Listing 27-10. Disabling Ajax for a Single Link

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="jquery.mobile-1.0.css" type="text/css" />
    <script type="text/javascript" src="jquery-1.6.4.js"></script>
    <script type="text/javascript" src="jquery.mobile-1.0.js"></script>    
</head>
<body>
    <div id="page1" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
           This is Jacqui's Flower Shop
           <p><a href="#page2">Go to page 2</a></p>
           <p><a href="document2.html" data-ajax="false">Go to document2.html</a></p>
        </div>
    </div>    
    <div id="page2" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
           This is page 2
           <p><a href="#page1">Go to page 1</a></p>
        </div>
   </div>    
</body>
</html>

In this example, I have disabled Ajax for the link that navigates to document2.html. As Figure 27-7 shows, this produces the expected navigation sequence.

Image

Figure 27-7. Disabling Ajax to avoid an element id conflict

You can turn off Ajax by default using the ajaxEnabled global setting, which is demonstrated in Listing 27-11. When this setting is false, Ajax will not be used for navigation unless you apply the data-ajax attribute to an element with a value of true.

Listing 27-11. Using the global Setting to Disable Ajax

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="jquery.mobile-1.0.css" type="text/css" />
    <script type="text/javascript" src="jquery-1.6.4.js"></script>
    <script type="text/javascript">
        $(document).bind("mobileinit", function() {        
            $.mobile.ajaxEnable = false
        })
    </script>

    <script type="text/javascript" src="jquery.mobile-1.0.js"></script>    
</head>
<body>
    <div id="page1" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
           This is Jacqui's Flower Shop
           <p><a href="#page2">Go to page 2</a></p>
           <p><a href="document2.html">Go to document2.html</a></p>
        </div>
    </div>    
    <div id="page2" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
           This is page 2
           <p><a href="#page1">Go to page 1</a></p>
        </div>
   </div>    
</body>
</html>
Prefetching Pages

You can ask jQuery Mobile to prefetch documents so that the pages they contain are immediately available when the user clicks a link. The advantage of this is that you create a more responsive application, but you do so by downloading content that the user may not navigate to. To demonstrate this feature, I created a document called singlepage.html, the content of which is shown in Listing 27-12.

Listing 27-12. The singlepage.html File

<!DOCTYPE html>
<html>
<head>
    <title>Single Page</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="jquery.mobile-1.0.css" type="text/css" />
    <script type="text/javascript" src="jquery-1.6.4.js"></script>
    <script type="text/javascript" src="jquery.mobile-1.0.js"></script>    
</head>
<body>
    <div id="page1" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
           This is the only page in this document
           <p><a href="example.html">Return to example.html</a></p>
        </div>
    </div>    
</body>
</html>

You enable prefetching by applying the data-prefetch attribute to the a element, as shown in Listing 27-13.

DECIDING WHETHER TO PREFETCH CONTENT

Listing 27-13. Prefetching Content

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="jquery.mobile-1.0.css" type="text/css" />
    <script type="text/javascript" src="jquery-1.6.4.js"></script>  
    <script type="text/javascript" src="jquery.mobile-1.0.js"></script>    
</head>
<body>
    <div id="page1" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
           This is Jacqui's Flower Shop
           <p><a href="#page2">Go to page 2</a></p>
           <p><a href="singlepage.html" data-prefetch>Go to singlepage.html</a></p>
        </div>
    </div>    
    <div id="page2" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
           This is page 2
           <p><a href="#page1">Go to page 1</a></p>
        </div>
   </div>    
</body>
</html>

In this example, I have asked jQuery Mobile to prefetch the target of my URL. When I click the link, jQuery Mobile is able to navigate to the prefetched content, avoiding any delay.

Image Tip It can be hard to be sure that features such as prefetching are working when you are developing on a fast, reliable network. I like to check these features by using a debugging HTTP proxy, which shows me the requests that are sent from the browser. If you are a Windows user, then I recommend Fiddler, which is an excellent tool that can be endlessly configured and customized. Fiddler can be downloaded from www.fiddler2.com.

Using Scripting to Control jQuery Mobile Pages

You don't always want to rely on the user clicking links to manage page navigation. Fortunately, jQuery Mobile provides you with methods and settings that allow you to control navigation using JavaScript. In the sections that follow, I'll show you how to take advantage of these methods to get fine-grained control over the navigation in a jQuery Mobile web application.

Changing the Current Page

The changePage method allows you to change the page that jQuery Mobile displays. Listing 27-14 shows the basic use of this method, which changes the displayed page based when a button is clicked.

Listing 27-14. Changing the Page That jQuery Mobile Displays

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="jquery.mobile-1.0.css" type="text/css" />
    <script type="text/javascript" src="jquery-1.6.4.js"></script>  
    <script type="text/javascript">
        $(document).bind("pageinit", function() {
           $('button').bind("tap", function(e) {
                var target = this.id == "local" ? "#page2" : "document2.html";
                $.mobile.changePage(target)
           })
        });
    </script>

    <script type="text/javascript" src="jquery.mobile-1.0.js"></script>
</head>
<body>
    <div id="page1" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
            <fieldset class="ui-grid-a">
                <div class="ui-block-a"><button id="local">Local</button></div>
                <div class="ui-block-b"><button id="remote">Remote</button></div>
            </fieldset>
        </div>

    </div>
    <div id="page2" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
           This is page 2
           <p><a href="#page1">Go to page 1</a></p>
        </div>
   </div>    
</body>
</html>

In this example, I have added two buttons that, when clicked, cause the changePage method to be called. To create this demonstration, I have used some jQuery Mobile features that I explain in later chapters. The event that I listen for using the bind method is tap, which is one of a small set of helpful custom events that jQuery Mobile defines. This event is triggered when the user taps the screen (or clicks the mouse on a nontouch device). I described this event, along with the rest of the jQuery Mobile events in Chapter 26.

The buttons are standard HTML elements that jQuery Mobile automatically converts into button widgets. I describe the options for configuring jQuery Mobile buttons in Chapter 29. Finally, you will notice that I have assigned some elements to the classes ui-grid-a, ui-block-a, and ui-block-b. These are part of the jQuery Mobile support for creating page layouts, which I describe in Chapter 28. Despite using features from future chapters, the result of this example is pretty simple, as Figure 27-8 shows. When the user clicks one of the buttons, the changePage method is called, passing either the id value of a local page or a URL of another document for jQuery Mobile to display. The content is loaded, and the transition effect is displayed, just as when you were using regular links.

Image

Figure 27-8. Using the changePage method

Now that you have seen the basic use of the changePage method, you can turn to the different configuration options available. To configure the page transition, you pass a settings object as the second argument to the changePage method, specifying values for one or more settings. Table 27-2 describes the settings that are available. Most of these settings are best left with their defaults, but in the sections that follow I show two of the settings that it can be useful to modify more frequently.

Image

Controlling the Direction of the Transition Effect

The reverse setting is the one I use most often. jQuery Mobile will always play transition effects in the same way, which doesn't always make sense when you have presented the user with an action that effectively sends them back to an earlier page or where you are responding to a jQuery Mobile swiperight event. Listing 27-15 shows the problem.

Listing 27-15. Transition Effect Direction Mismatched with Navigation Intent

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="jquery.mobile-1.0.css" type="text/css" />
    <script type="text/javascript" src="jquery-1.6.4.js"></script>  
    <script type="text/javascript">
        $(document).bind("pageinit", function() {
           $('button').bind("tap", function(e) {
                var target = this.id == "forward" ? "#page2" : "#page1";
                $.mobile.changePage(target, {
                    reverse: (target == "#page1")
                });
           })
        });
    </script>

    <script type="text/javascript" src="jquery.mobile-1.0.js"></script>    
</head>
<body>
    <div id="page1" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
            This is page 1            
            <button id="forward">Go to Page 2</button>
        </div>
    </div>    
    <div id="page2" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
            This is page 2
            <button id="back">Back to Page 1</button>
        </div>
   </div>    
</body>
</html>

There are two pages in this document, each of which contains a button that navigates to the other page. The button on the second page is labeled Back to Page 1. When the button on the second page is clicked, I change the direction of the transition effect by using a reverse value of true. I can't show this effect on a static page, but the effect feels much more natural. There is some subconscious expectation formed about the animation should be played in based on the navigational cue that you are returning to a previous page, rather than progressing to a new one. You will understand exactly what I mean if you view this example in a browser.

Controlling the Load Dialog

jQuery Mobile displays a dialog box when it loads a remote document via Ajax for longer than 50 milliseconds. When using a mobile browser emulator and a fast network, jQuery Mobile is able to load the document so quickly that the dialog box is never shown. But if you use an actual mobile data network or, as I have done, introduce a delay into the request, then the dialog remains on the screen long enough to be seen, as Figure 27-9 illustrates.

Image

Figure 27-9. The jQuery Mobile loading dialog box

You can change the period after which the dialog is displayed by providing a value for the loadMsgDelay setting, as shown in Listing 27-16.

Listing 27-16. Changing the Delay for the Loading Dialog

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="jquery.mobile-1.0.css" type="text/css" />
    <script type="text/javascript" src="jquery-1.6.4.js"></script>  
    <script type="text/javascript">
    
        $(document).bind("mobileinit", function() {
            $.mobile.loadingMessage = "Loading Data..."
        })

        $(document).bind("pageinit", function() {
           $('button').bind("tap", function(e) {
                $.mobile.changePage("document2.html",{
                    loadMsgDelay: 1000
                });

           })
        });
    </script>
    <script type="text/javascript" src="jquery.mobile-1.0.js"></script>    
</head>
<body>
    <div id="page1" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">   
            <button id="forward">Go</button>
        </div>
    </div>    
</body>
</html>

In this example, I have specified that jQuery Mobile should wait for one second before displaying the loading dialog to the user.

Image Tip You can change the text in the loading dialog by setting a new value for the global loadingMessage property, as shown in the example. As with all jQuery Mobile global properties, this should be set in a function executed when the mobileinit event is triggered.

You can disable this dialog by specifying false for the showLoadMsg setting when you call the changePage method. This is not something I recommend doing, because providing the user with feedback is always a good thing, but Listing 27-17 shows the setting in use.

Listing 27-17. Disabling the Loading Dialog

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="jquery.mobile-1.0.css" type="text/css" />
    <script type="text/javascript" src="jquery-1.6.4.js"></script>  
    <script type="text/javascript">
        $(document).bind("pageinit", function() {
           $('button').bind("tap", function(e) {
                $.mobile.changePage("document2.html",{
                    showLoadMsg: false
                });

           })
        });
    </script>
    <script type="text/javascript" src="jquery.mobile-1.0.js"></script>    
</head>
<body>
    <div id="page1" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">   
            <button id="forward">Go</button>
        </div>
    </div>    
</body>
</html>

Determining the Current Page

You can use the $.mobile.activePage property to determine the current page that jQuery Mobile is displaying. I have included this property for completeness, but it is not something I find myself using very often. My jQuery Mobile applications tend to consist of small, simple pages that contain very little scripting and a small number of widgets. In my experience, needing to work out where you are is something that arises for more complex applications. There are no hard and fast rules about how complex a mobile web application can be, but if you find yourself in need of this property, then I suggest you take a quick moment to sanity check your approach. You might be trying to do something this is too complex for mobile browsers or (more likely) something that can be handled without using JavaScript. Listing 27-18 shows the use of the activePage property.

Listing 27-18. Using the activatePage Property

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="jquery.mobile-1.0.css" type="text/css" />
    <script type="text/javascript" src="jquery-1.6.4.js"></script>  
    <script type="text/javascript">
        $(document).bind("pageinit", function() {
           $('button').bind("tap", function(e) {
                var nextPages = {
                    page1: "#page2",
                    page2: "#page3",
                    page3: "#page1"
                }
                var currentPageId = $.mobile.activePage.attr("id");
                $.mobile.changePage(nextPages[currentPageId])
           })
        });
    </script>
    <script type="text/javascript" src="jquery.mobile-1.0.js"></script>    
</head>
<body>
    <div id="page1" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
            This is page 1
            <button id="forward">Go</button>
        </div>
    </div>
    <div id="page2" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
            This is page 2
            <button id="forward">Go</button>
        </div>
    </div>
    <div id="page3" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">
            This is page 3
            <button id="forward">Go</button>
        </div>
    </div>      
</body>
</html>

There are three pages in this example, each of which has a button. When the button is clicked, I read the activePage property to get the current page. The activePage property returns a jQuery object that contains the current page, so I use the jQuery attr method to get the value of the id attribute.

My script includes a simple map that tells me what the next page should be for each of the pages in my document, and I use the id value obtained from the activePage property as the argument to the changePage method, ensuring that I progress through my pages in the sequence defined by my map.

Loading Pages in the Background

You can use the loadPage method to load remote documents without displaying them to the user. This is the programmatic equivalent of the prefetching that I demonstrated earlier in the chapter. The loadPage method takes two arguments. The first is the URL of the document to load, and the second is an optional settings object. The loadPage method supports a subset of the settings used by the changePage method: data, reloadPage, and type. Listing 27-19 shows the loadPage method in use.

Listing 27-19. Using the loadPage Method

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="jquery.mobile-1.0.css" type="text/css" />
    <script type="text/javascript" src="jquery-1.6.4.js"></script>  
    <script type="text/javascript">
        var loadedPages = false;
    
        $(document).bind("pageinit", function() {
            if (!loadedPages) {
                loadedPages = true;            
                var pload = $.mobile.loadPage("document2.html")
                pload.done(function() {
                    $('#gobutton').button("enable").bind("tap", function() {
                        $.mobile.changePage("document2.html")
                    })
                })
            }
        });
    </script>
    <script type="text/javascript" src="jquery.mobile-1.0.js"></script>    
</head>
<body>
    <div id="page1" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">   
            <button id="gobutton" disabled>Go</button>
        </div>
    </div>    
</body>
</html>

In this example, I use the loadPage method to preload the document2.html file. The loadPage method returns a deferred object that you can use to receive notification when the page has loaded. I explain deferred objects in Chapter 35, but for now it is enough to know that you can call the done method on the object returned by the loadPage method, specifying a function that will be executed when the Ajax request started by loadPage has completed.

In this example, I use the enable method on the jQuery UI button widget to enable a button in the page and to register a handle for the tap event. When the button is clicked, I call the changePage method to navigate to the prefetched document.

Notice that I have defined a global variable called loadedPages. The pageinit event is triggered whenever jQuery Mobile initializes a page. This means the event is triggered when the document in the example is loaded and again when loadPage loads document2.html via Ajax. I use the loadedPages variable to ensure that I try to preload the content only once. It wouldn't be the end of the world to call loadPage twice (which is what would happen without the loadedPages variable) unless I enabled the reload setting. This would cause the cached copy of the document to be ignored and transfer document.html twice. I explain the set of jQuery Mobile page events in the following section.

Using Page Events

jQuery Mobile defines a set of events that you can use to receive notifications about change in pages. These events are described in Table 27-3, and I demonstrate some of the more useful ones in the sections that follow.

Image

Handling the Page Initialization Event

The pageinit event is the most useful of the jQuery Mobile page events. It is this event that you respond to when you want to configure your page using a script. I am not going to demonstrate this event again because you have seen it in every example so far, but I will emphasize that using the standard jQuery $(document).ready() approach is not reliable when working with jQuery Mobile.

Handling Page Load Events

The pagebeforeload, pageload, and pageloadfailed events can be useful for monitoring Ajax requests made for remote pages, either automatically generated by jQuery Mobile or programmatically via the changePage and loadPage methods. When demonstrating the loadPage method, I used a deferred object to respond when the page had been loaded, but you can achieve the same result using the pageload method (and, of course, the pageloadfailed method when things go wrong). Listing 27-20 shows the loadPage example updated to use the pageload event.

Listing 27-20. Using the pageload Event

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="jquery.mobile-1.0.css" type="text/css" />
    <script type="text/javascript" src="jquery-1.6.4.js"></script>  
    <script type="text/javascript">

        $(document).bind("pageload", function(event, data) {
            if (data.url == "document2.html") {
                $('#gobutton').button("enable").bind("tap", function() {
                    $.mobile.changePage("document2.html")
                })
            }
        })


        var loadedPages = false;    
        $(document).bind("pageinit", function() {
            if (!loadedPages) {
                loadedPages = true;            
                $.mobile.loadPage("document2.html")
            }
        });
    </script>
    <script type="text/javascript" src="jquery.mobile-1.0.js"></script>    
</head>
<body>
    <div id="page1" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">   
            <button id="gobutton" disabled>Go</button>
        </div>
    </div>    
</body>
</html>

In this example, I have specified a function that will be executed when the pageload event is triggered. jQuery Mobile provides information about the request by passing a data object as the second argument to the function. I use the url property to check that the document that has been loaded is the one I am expecting. The set of properties defined by the data object for the pageload event is described in Table 27-4. You can see from the table that most of the properties correspond to the jQuery Ajax support, which I described in Chapters 14 and 15.

Image

Responding to Page Transitions

You can use the page transition events to be notified when the user navigates from one page to another (or when you do this programmatically using the changePage method). These events (pagebeforehide, pagehide, pagebeforeshow and pageshow) are triggered for every page transition, even if the page has been displayed to the user before. Listing 27-21 shows the use of one of these events.

Listing 27-21. Responding to a Page Being Hidden

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="jquery.mobile-1.0.css" type="text/css" />
    <script type="text/javascript" src="jquery-1.6.4.js"></script>  
    <script type="text/javascript">
        var registeredHandlers = false;    
        $(document).bind("pageinit", function() {
            if (!registeredHandlers) {
                registeredHandlers = true;                        
                $('#page1').bind("pagehide", function(event, data) {
                    $.mobile.changePage($("#page1"))
                })
            }
        });
    </script>

    <script type="text/javascript" src="jquery.mobile-1.0.js"></script>    
</head>
<body>
    <div id="page1" data-role="page">
        <div data-role="header">
           <h1>Jacqui's Shop</h1>
        </div>        
        <div data-role="content">   
            <a href="document2.html">Go to document2.html</a>
        </div>
    </div>    
</body>
</html>

In this example, I register a handler function for the pagehide event on the page1 element, by selecting the element I want and calling the bind method. This means I will receive the event only when that selected page is hidden. This is a pretty dumb example, because it simply uses the changePage method to return to page1 whenever the pagehide event is triggered, but it does demonstrate the use of the event. Notice that I am still using a variable to ensure that I register my handler function only once. If I did not do this, then two functions would be registered for the same event on the same element when document2.html page is loaded.

Image Tip jQuery Mobile provides additional information about the page transition events by passing a data object as the second argument to the handler function. This object will define a property called either nextPage (for the pagebeforehide and pagehide events) or prevPage (for pagebeforeshow and pageshow). These properties return a jQuery object containing the page element that has just been hidden or shown.

Summary

In this chapter, I described pages, which are one of the key building blocks of jQuery Mobile. The idea of having multiple pages in a single document is something that is unique to jQuery Mobile and that can be helpful for small and simple applications. But for more serious efforts, putting pages in their own document and relying on jQuery Mobile to load them via Ajax is the way to go.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.242.157