Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile

PhoneGap and Jquery Mobile – A Truly Winning Combination

3.12/5 (3 votes)
22 Nov 2015CPOL5 min read 4.7K  
Any regular readers may have noticed that I finally got around to updating and adding a new book under My Books on the right-hand side of the screen.

Image 1 Any regular readers may have noticed that I finally got around to updating and adding a new book under "My Books" on the right-hand side of the screen.  Yes, I not-so recently published my third book (and second with O'Reilly) earlier this year.

The book is called 20 Recipes for Programming PhoneGap – Cross-Platform Mobile Development for Android and iPhone.  Throughout this book, I get you up and running quickly using the PhoneGap API along with the Jquery Mobile API to take care of the pesky mobile design issues.

Much like I did when I released my MVC 3.NET book, I provided a free chapter from the book for my readers.  Well here is an excellent recipe sample from my PhoneGap book.  The goal of this recipe is to provide a standard approach to automatically fire (or trigger) a JavaScript function when a PhoneGap page has loaded – either on initial launch or after the user has navigated within the application.

Executing a Callback Function Once the Device Is Ready

Problem

After a page has loaded, you will want to execute some JavaScript code immediately without invoking it manually each time in your JavaScript code.

Solution

Because HTML doesn’t allow for a lot of dynamic features, a lot of code needs to be duplicated. To minimize the page load times, you should load the minimal amount of content each time while reusing as much code as you can. The common.js JavaScript file must be kept lightweight, and additional JavaScript files should be created for other new functionality. However, there currently is no process to allow for additional function calls once the application has determined that the device is ready.

You can update the common.js JavaScript file with an automatic callback function that will be executed once the common code to detect the device type, network connection, etc., has finished working. This will enable you to use the same process in many future recipes.

Discussion

Because the application is using jQuery mobile, you must reorganize some of the existing code in order to improve code loading. When you navigate between pages using jQuery mobile, it performs the request via AJAX and strips all of the content from the HTML file (unless it is within a div tag that contains a data-role of type page). This Executing a Callback Function Once the Device Is Ready means that the previous window.onload event will no longer trigger. Instead, a new event that is provided by the jQuery mobile library will be used.

The first thing to note is that the index.html page from “Creating a Persistent Navigation System” on page 5 requires some reformatting as follows:

<!DOCTYPE HTML>
<html>
    <head>
        <title>PhoneGap</title>
        <link rel="stylesheet" href="css/jquery.mobile-1.0rc1.min.css" />
        <script type="text/javascript" charset="utf-8" src="scripts/phonegap-1.0.0.js"></script>
    </head>
    <body>
        <div data-role="page" id="index-page">
            <h1>Hello World!</h1>
            <div data-role="footer" data-position="fixed">
                <div data-role="navbar">
                    <ul>
                        <li>
                            <a href="index.html">Home</a>
                        </li>
                        <li>
                            <a href="about.html">About</a>
                        </li>
                    </ul>
                </div>
            </div>
        </div>
        <script type="text/javascript" charset="utf-8" src="scripts/jquery-1.6.4.min.js"></script>
        <script type="text/javascript" charset="utf-8" src="scripts/jquery.mobile-1.0rc1.min.js"></script>
        <script type="text/javascript" charset="utf-8" src="scripts/common.js"></script>
    </body>
</html>


Several things have changed in this code. Most of the JavaScript files have been moved out of the head tag. I’ve left the main PhoneGap file there to ensure that it loads completely before the page does, because anything placed inside the head tag must fully finish loading before you continue. Next, a new div tag was added with a data-role of type page. Finally, the previous JavaScript files have been moved to the bottom and the order has been altered. These have also been placed outside of the page div tag, because they do not need to be loaded again if the user navigates back to the index page. The order of the files was altered because, in the next example, the common.js file will be updated to use elements of jQuery and the mobile library, which must load first.

Within the next example is an updated common.js file. It contains all of the code from the first several recipes that performs the following operations: device ready, device detection, and network detection, as well as the new callback feature. The key objective of this expanded code is to allow you to run custom code tied to the name of a particular page, when that page loads.

JavaScript
// Global variable that will tell us whether PhoneGap is ready
var isPhoneGapReady = false;
// Default all phone types to false
var isAndroid = false;
var isBlackberry = false;
var isIphone = false;
var isWindows = false;

// Store the device's uuid
var deviceUUID;

// Store the current network status
var isConnected = false;
var isHighSpeed;
var internetInterval;

var currentUrl;

function init(url) {
    if (typeof url != 'string') {
        currentUrl = location.href;
    } else {
        currentUrl = url;
    }

    if (isPhoneGapReady) {
        onDeviceReady();
    } else {

        // Add an event listener for deviceready
        document.addEventListener("deviceready", onDeviceReady, false);
    }
}

function onDeviceReady() {
    // set to true
    isPhoneGapReady = true;
    deviceUUID = device.uuid;

    // detect the device's platform
    deviceDetection();

    // detect for network access
    networkDetection();

    // execute any events at start up
    executeEvents();

    // execute a callback function
    executeCallback();
}

function executeEvents() {
    if (isPhoneGapReady) {
        // attach events for online and offline detection
        document.addEventListener("online", onOnline, false);
        document.addEventListener("offline", onOffline, false);

        // set a timer to check the network status
        internetInterval = window.setInterval(function() {
            if (navigator.network.connection.type != Connection.NONE) {
                onOnline();
            } else {
                onOffline();
            }
        }, 5000);
    }
}

function executeCallback() {
    if (isPhoneGapReady) {
        // get the name of the current html page
        var pages = currentUrl.split("/");
        var currentPage = pages[pages.length - 1].slice(0, pages[pages.length - 1].indexOf(".html"));

        // capitalize the first letter and execute the function
        currentPage = currentPage.charAt(0).toUpperCase() + currentPage.slice(1);

        if (typeof window['on' + currentPage + 'Load'] == 'function') {
            window['on' + currentPage + 'Load']();
        }
    }
}

function deviceDetection() {
    if (isPhoneGapReady) {
        switch (device.platform) {
            case "Android":
                isAndroid = true;
                break;
            case "Blackberry":
                isBlackberry = true;
                break;
            case "iPhone":
                isIphone = true;
                break;
            case "WinCE":
                isWindows = true;
                break;
        }
    }
}

function networkDetection() {
    if (isPhoneGapReady) {
        // as long as the connection type is not none,
        // the device should have Internet access

        if (navigator.network.connection.type != Connection.NONE) {
            isConnected = true;
        }

        // determine if this connection is high speed or not
        switch (navigator.network.connection.type) {
            case Connection.UNKNOWN:
            case Connection.CELL_2G:
                isHighSpeed = false;
                break;
            default:
                isHighSpeed = true;
                break;
        }
    }
}

function onOnline() {
    isConnected = true;
}

function onOffline() {
    isConnected = false;
}

// This gets called by jQuery mobile when the page has loaded
$(document).bind("pageload", function(event, data) {
    init(data.url);
});

// Set an onload handler to call the init function
window.onload = init;

There is quite a bit happening in the preceding code. I will start at the bottom with the two events that call the init function. The window.onload code remains as-is and will be called when the application first loads. By binding the pageload event to the document, I ensure that each time a user clicks a new link, this event will fire when that page has finished loading. It is also passing the current URL to the updated init function.

This will be used for implementing the callback function. The init function has been updated to accept this new url parameter. However, since this parameter is not passed in by the window.onload event, the code checks to see whether it is a string. When a string is not detected (i.e., on first load), the location.href is used and stored in the currentUrl global variable. Then, if the variable isPhoneGapReady is already set and true, there is no need to add the listener and wait, so it just calls the onDeviceReady function.

The onDeviceReady function has been slightly reorganized and some of the previous work has been moved into new functions for later expansion, including the newly added executeCallback function.

The executeCallback function takes the currentUrl variable and splits it into parts to be able to retrieve just the filename, e.g., the index. This name is then used to check whether there is a function called onIndexLoad. If this function exists, it is executed.

When you add future pages, you can also add new functions that will be executed automatically once the page loads. These will perform any additional processing required by that page. For instance, if you add an onAboutLoad function, the app will execute it when about.html has finished loading.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)