jQtouch Dynamic Menus again

In the last part I concentrated on how to load and unload menus by binding to events. This time I’m focusing on loading the data for our menus. I want to achieve the following:

  1. Get data for our menus using an ajax call
  2. Use local storage to cache results
  3. Create an easy to use method to get and display data

I would like to make one function call that will give me menu data. I want the ajax loading to be handled behind the scenes. So I’m really looking for this kind of code

 Javascript |  copy code |? 
01
db = new DB();
02
db.createFruitTable();
03
$('#jqt').append('<div class="progress"></div>');
04
db.getFruitList(
05
     function(trans, result) {
06
          for(var i=0;i<result.rows.length;i++) {
07
                   var li = $('<li></li>');
08
                   li.append('<a>' + result.rows.item(i).name + '</a>');
09
                   li.addClass('arrow');
10
                   li.appendTo($('#fruitMenu'));
11
          }
12
          $('.progress').remove();
13
     });

I’ll always treat the result of getFruitList() as a database result set. If we have just started our app, then getFruitList should be responsible for populating that result set from the database, or via AJAX. This is how I’ve done the database and ajax code for the getFruitList function.
If there are no entries in the local storage:

  1. Bind to the ‘fruitListPopulated’, with the users callback function in the event data, and run getFruitList once more.
  2. Make an ajax call, and pass ‘insertFruit’ as the success function
  3. insertFruit will insert whatever data, and trigger the ‘fruitListPopulated’ event, which will run getFruitList once more.
  4. Now we should have results in the database

So this is what our database code should resemble:

 Javascript |  copy code |? 
01
this.getFruitList = function(callback) {
02
 
03
  /* We lose 'this' context after the database call, and if we have to make an ajax
04
      call and use our event callback, 'this' will also be invalid.  So we have to pass
05
      along the context as data in our event. */
06
  var ctx;
07
  if( typeof callback == 'object' ) ctx = callback.data.context;
08
  else ctx = this;
09
 
10
  try {
11
    ctx.dbh.transaction(
12
             function(trans) {
13
                 trans.executeSql('SELECT * FROM fruit', [],
14
                                  function(t,r) {
15
                                      /* If we had no results, we'll have to load the list by an ajax call. */
16
                                      if( r.rows.length == 0 ) {
17
                                          $('#fruitList').bind('fruitListPopulated', {cb: callback, context: ctx}, ctx.getFruitList);
18
                                          $.ajax(
19
                                                {url: 'http://theurl/fruitlist/',
20
                                                 type: "GET",
21
                                                 dataType: "json",
22
                                                 contentType: "application/json; charset=utf-8",
23
                                                 success: ctx.insertFruit,            // This function should insert the fruit, and trigger our event when done
24
                                                 error: function(xhr, txt, err) {
25
                                                           alert('Database unreachable, try again!' + txt + err);
26
                                                        }
27
                                                });
28
                                      } else {
29
                                          /* If we have results, call the user's callback. It may be in the event
30
                                             data, if we are coming from the ajax call. */
31
                                          if( typeof callback == 'function' ) callback(t,r);
32
                                          if( typeof callback == 'object' ) {
33
                                              $('#fruitList').unbind('fruitListPopulated');
34
                                              callback.data.cb(t,r);
35
                                          }
36
                                      }
37
                                  },
38
                                  function(t, res) { debug.error('Error reading DB: ' + res); });
39
                          });
40
  } catch (e) {
41
       debug.error('DB error: ' + e);
42
  }
43
};    
44

We can use this pattern over and over to load the list on startup, or to refresh the list on the users command.

What about invalidating the cached objects in the database? Well, that all depends on your data. I simply include a button that deletes all the rows from whichever SQL table, then the next time you grab this list, it has to refresh via AJAX.
here

Posted Friday, June 11th, 2010 under jqTouch.

Leave a Reply