You are here

Playtime with Cordova: pt.5 Cordova, jQuery mobile, SQLite and dynamic data-driven pages

Friday, July 18, 2014

DISCLAIMER: This is me sharing my learning, I have not yet created a final application, and also, some of the process’ below may not be best practice.  BUT as a place to start playing, which is really what we all want to do, I think it works.

As I am feeling particularly lazy right now, I am going to start by quoting my previous (part 3) article.

 

“have a read of this, as we will be doing some dynamic generation of pages soon using data from a csv file (both local, and a remote one).

http://demos.jquerymobile.com/1.1.1/docs/pages/page-dynamic.html

 

The main things to take home in there are how the ‘pagebeforechange’ binding is required, aswell as the ‘enhancement’ parts.  The enhancements are needed, as it triggers the jQuery mobile functionality to get all the layouts and listeners behaving on your new page as if it was hard coded.”

 

So, what I want to have are some pages which generate dynamically.  I wont get you a tidied project here, but you will have enough to see how it all ties together and get building some cool stuff.  We begin with creating a csv, you will likely want to think long-term with this, so maybe create a spreadsheet in google docs and export from there so you/client can easily update in the future.  My system was a set of recipes, each having ingredients and steps attached to it.  So let’s start with our recipe csv file, and get it looking like this:

id,name

1,recipe 1

2,recipe 2

3,recipe 3

4,recipe 4

5,recipe 5

6,recipe 6

7,recipe 7

8,recipe 8

Save this into a folder in your www folder, I used www/data/recipes.csv for my app.  

We then want to quickly add our page placeholder to the template in index.html. use something like this:

       <div data-role="page" id="recipe">

           <div data-role="header">

               <h1>Recipe</h1>

               <a href="#recipes" class="ui-btn-left">Recipes</a>

           </div>

           <div data-role="main">

           </div>

       </div>

 

Now we create our bind listener to tell it to keep an eye on that query string, and do some exciting stuff when it needs to

   // Listen for any attempts to call changePage().

   $(document).bind("pagebeforechange", function(e, data) {

       // Check page is loaded by url

       if (typeof data.toPage === "string") {

           var u = $.mobile.path.parseUrl(data.toPage);

           var res = /^#recipes$/;

           if (u.hash.search(res) !== -1) {

               // Load page content

               showRecipes(u, data.options);

               // Disable defaults

               e.preventDefault();

           }

       }

   });

Next we want to setup the function which gets run when that triggers

   function showRecipes(urlObj, options) {

       var pageSelector = urlObj.hash.replace(/\?.*$/, "");

       // Set some global variables for other functions

       // (there is a better way to do this somewhere)

       window.urlObj = urlObj;

       window.options = options;

       // Get the page we are going to dump our content into.

       var $page = $(pageSelector);

       window.output = '<p>some intro copy goes here</p>';

       // Populate ingredients -> populate steps -> render page

       // These COULD be nested all in one command if preferred

       dbShell.transaction(populateRecipes, errorCB);

   }

 

Nearly there, now let’s get our content into the output variable

   function populateRecipes(tx) {

       // Get recipes

       tx.executeSql('SELECT * FROM recipes', [], function(tx, results) {

           if (results.rows.length > 0) {

               window.output = '<h2>Recipes</h2>';

               window.output += '<ul data-role="listview" data-inset="true">';

               for (var i = 0; i < results.rows.length; i++) {

                   window.output += '<li class="recipe-item recipe-item-' + results.rows.item(i).rid + '"><a href="#recipe?rid=' + results.rows.item(i).rid + '">' + results.rows.item(i).name + ' (' + results.rows.item(i).rid + ')' + '</a></li>';

               }

               window.output += '</ul>';

           } else {

               window.output = 'Sadly there are no recipes in the database';

           }

           // Render the page

           renderDynamicPage();

       }, errorCB);

   }

 

Run the final renderer for the content

   function renderDynamicPage() {

       urlObj = window.urlObj;

       var pageSelector = urlObj.hash.replace(/\?.*$/, "");

       // Get the page we are going to dump our content into.

       var $page = $(pageSelector);

       var $header = $page.children(":jqmData(role=header)");

       var $content = $page.children(":jqmData(role=main)");

       // Set the header and content

       $header.find("h1").html("the title");

       $content.html(window.output);

       // 'Enhance' the page and listview

       $page.page();

       $content.find(":jqmData(role=listview)").listview();

       // We don't want the data-url of the page we just modified

       // to be the url that shows up in the browser's location field,

       // so set the dataUrl option to the URL for the category

       // we just loaded.

       options.dataUrl = urlObj.href;

       // Change the page using variables

       $.mobile.changePage($page, options);

   }

});

 

Useful resources

Related: 

Blog & News

Monday, March 7, 2016

Okay, I know it is awful practice to put 2 things into one article, but I didn't want to write two tbh, so I will keep this tidy, and you can grab out what you need.

 

Subscribe to Blog & News

About

Cultivating a better future, with the seeds of better websites

For several years I have evolved through one of the largest media charities in the UK to the role of Senior developer.  I loved it there, but have to stepped out on my own as a freelance developer.

My main skills are with the Drupal CMS, developing code for it, ensuring standards through projects (whether that design, development, or planning), and leading teams to build applications they can be proud of.

Digital Consultancy, Web Development and Project Architecture are where I try to focus my skills, supporting my passion and desire to create stunning websites on time, in budget, and meeting your objectives.

To build a powerful web presence, I combine my creative, technical, and managerial experience (alongside a good splash of passion) which I have cultivated over 10 years in the industry, creating websites people want to shout about.

More on how I can help