Create Your First Mobile App with PhoneGap Build – Using the Storage API

By Brian Rinaldi

This is part 6 in an ongoing series. You can find part 1 herepart 2 herepart 3 herepart 4 here and part 5 here. The files for the sample app are available here.

Even though our app is now looking and feeling more like an app, the truth is that everything up to this point could have been (and arguably should have been) accomplished via a web page. We’re not using any device features or doing anything that couldn’t be accomplished within the device browser. In this step, we will begin to access some device features via the PhoneGap API for storage. Using this API, we’ll add a local database that will store records of our favorite GitHub repositories.

Interestingly enough, the local database feature also works perfectly fine in your desktop browser, so any code from this step can be tested in your browser. The PhoneGap API, in this case, simply overcomes browser support across various devices as on some device browsers, this feature is not supported.

The first thing we will do is add some JavaScript code to create our local database on jQuery Mobile’s “pageinit” event. Since creating the database is asynchronous, we’ll need four methods, the first opens the connection to the database which then calls another method that submits the SQL for our database transaction. The third method simply does a console log of any error should one occur (obviously, a real application should handle errors more gracefully). Similarly the fourth method is just a success handler that will be called if the transaction succeeds and currently only logs a message of “success.” You will need to add this code to index.js with “pageinit” event binding below overwriting the existing method.

var db;

$('#reposHome').bind('pageinit', function(event) {
    loadRepos();
    db = window.openDatabase("repodb","0.1","GitHub Repo Db", 1000);
    db.transaction(createDb, txError, txSuccess);
});

function createDb(tx) {
    tx.executeSql("DROP TABLE IF EXISTS repos");
    tx.executeSql("CREATE TABLE repos(user,name)");
}

function txError(error) {
    console.log(error);
    console.log("Database error: " + error);
}

function txSuccess() {
    console.log("Success");
}

In order to allow the user to save a project as a favorite, we will add a button in repo-detail.html to the page header (that is the div with a data-role of “header”). You may notice that we are using one of the data properties on the button to set the icon to be a star (suitable for saving a favorite) and to align the button on the right-hand side of the header.

<button id="saveBtn" data-icon="star" class="ui-btn-right">Save as Favorite</button>

Currently, this button does nothing as we have not added any code to respond to the user touching or clicking the button. First, let’s add some JavaScript methods to insert data into the database when called. We’ll perform another database transaction similar to the previous transaction where we created the database. Add the following code to index.js.

function saveFave() {
    db = window.openDatabase("repodb","0.1","GitHub Repo Db", 1000);
    db.transaction(saveFaveDb, txError, txSuccessFave);
}

function saveFaveDb(tx) {
    var owner = getUrlVars().owner;
    var name = getUrlVars().name;

    tx.executeSql("INSERT INTO repos(user,name) VALUES (?, ?)",[owner,name]);
}

function txSuccessFave() {
    console.log("Save success");

    disableSaveButton();
}

Now when the reposDetail page is shown (i.e. the “pageshow” event), we need to add a click event handler to the button so that it responds to the user. Add the following line within our existing “pageshow” handler for the reposDetail page.

$("#saveBtn").bind("click", saveFave);

In the txSuccessFave() method earlier, you may have noticed we called a nonexistent method called disableSaveButton(). Let’s add this function which will change the text of the button to “saved” after the user saves an item, as well as change the color of the button and make it inactive for click events. (If you are wondering why this code seems slightly complicated, see the discussion on jQuery Mobile Generated HTML and Styles below).

function disableSaveButton() {
    // change the button text and style
    var ctx = $("#saveBtn").closest(".ui-btn");
    $('span.ui-btn-text',ctx).text("Saved").closest(".ui-btn-inner").addClass("ui-btn-up-b");

    $("#saveBtn").unbind("click", saveFave);
}

At this point, the favorites will save properly, but when you visit a favorite the button still reads “Save Favorite” rather than “Saved.” In order to correct this, we need to check if we have already saved this project when the page loads. In order to do that, let’s add a line to call to a new method in our “pageshow” event handler for reposDetail.

checkFave();

This method and its associated callbacks will query the database to see if an item with the same username and repository name has already been saved in our local database.

function checkFave() {
    db.transaction(checkFaveDb, txError);
}

function checkFaveDb(tx) {
    var owner = getUrlVars().owner;
    var name = getUrlVars().name;

    tx.executeSql("SELECT * FROM repos WHERE user = ? AND name = ?",[owner,name],txSuccessCheckFave);
}

function txSuccessCheckFave(tx,results) {
    console.log("Read success");
    console.log(results);

    if (results.rows.length)
         disableSaveButton();
}

This last method calls the disableSaveButton() method we created earlier if there are any results returned (i.e. if the item has already been saved).

Since the local database functionality works within your browser, you can feel free to test this in the browser first to see if everything works. Once you’ve confirmed that everything function, zip up your project and upload it to PhoneGap Build. When hydration is complete, open the app on your device and it should update. You can see a screenshot of our updated project details page with a saved favorite running in the browser below.

step4

In future updates we should not recreate the database every time the app is loaded, as this overwrites any pre-existing favorites.  Also, we might consider consolidating and/or improving our database transaction callback handlers.

jQuery Mobile Generated HTML and Styles

You may have noticed that the jQuery code we used to change our button text to read “Saved” seemed overly complex. Rather than just simply selecting the button by it’s ID, we are using methods like closest() to traverse the DOM and locate our button text (as an aside, there are instructions on how to do this available here). The reason this happens is because jQuery Mobile automatically adds a bunch of generated HTML and CSS styles to your HTML to make it look and feel like a mobile app.

As mentioned earlier, this can make jQuery Mobile very easy to use but can make some seemingly simple tasks such as this more complicated than you might anticipate. You will frequently need to reference the generated HTML via your browser’s developer tools or the PhoneGap debugging tools discussed earlier in order to determine the actual jQuery selectors necessary to achieve the effect you desire.

PhoneGap API Explorer

PhoneGap comes with a long list of supported API’s of which I only cover a couple here. The PhoneGap documentation is really good at showing how to use the API’s, however if you want to actually see how they work on your device, I highly recommend using an app created by Adobe evangelist Christophe Coenraets called the PhoneGap API Explorer.

This app not only shows you how to use PhoneGap’s API’s but allows you to enter parameters and run them on your device to see the result. This app is available for free on the iOS App Store and on Google Play. It is also posted as an open-source project on GitHub.

pgapi_sql

In part 7 we’ll add another page for viewing favorites and integrate PhoneGap’s API for notifications. View Part 7 here.

Modern Web Newsletter

Subscribe to receive the Modern Web tutorials, sent out every second Wednesday.

  • http://www.abc.com tarek

    What happens when an update to an app like this made? Does the local storage data persist?

  • remotesynth

    Yes, Tarek, local storage data will persist. As noted, in my sample app, I am currently recreating the database when the app loads which will erase the data. For a real application, you’d want to modify that code to only create the table or update it if changes hav been made to the data structure.

  • Ben Burwick

    The link to “View Part 7″ goes to part 6. Yes, I should probably review the material again, but I’m getting dizzy. ;-)

  • Kal

    Brian,
    The link to part 7 points to part 6. Here’s the correct link http://flippinawesome.org/2013/04/29/phonegap-build-step-7/

  • remotesynth

    Sorry about the link error. It has been fixed.

  • http://www.missioncomplete.com Stephen Lambert

    First of all, THANK YOU SO MUCH FOR THESE TUTORIALS! They are beyond excellent.

    I may have missed it, but is there an easy way (software or extension for a browser) to view storage api / local database tables as the app creates and modifies them? Sort of a “phpmyadmin” for this kind of storage?

  • remotesynth

    @stephen – Glad they are helpful to you. In the browser, you can view local storage and local databases via the developer tools. In Chrome they are listed under the Resources tab. I don’t recall offhand if this is available in Weinre or other remote debugging options but you can see all the debugging tools available here https://github.com/phonegap/phonegap/wiki/Debugging-in-PhoneGap

Top