jQuery Mobile and Dynamic Data

23rd May, 2011 - Posted by david

UPDATE: I’ve recently been asked by entertainment.ie to stop scraping thier licensed data, to which I’ve duly agreed. Thus, the app is no longer live. However, the lessons learned below are still valid. END

Haven’t posted for a while, mainly because I’ve been busy trying to teach myself Ruby on Rails, so haven’t created anything new in my spare time. Have come up with a few interesting fixes/ways to do things in relation to Facebook code in work though, so will hopefully do a post on those in the near future.
In the meantime, I wrote a very small little web application last week using the pretty cool jQuery Mobile framework. The app, called What’s on now (link removed, see UPDATE above), is simply a list of what’s on now and next on Ireland’s 17 basic cable channels. The data is pulled from a similar page on entertainment.ie, with the unnecessary channels filtered out. At the moment the app is pretty simple, but I plan to add to it over time (e.g. to add an option for the non-basic channels), updating this article as I go.

I did this mainly to have a quick go with jQuery Mobile, to see what it could do. I could’ve used PHP and built a mobile-sized HTML page, but it’s always good to try new things! Most of the development was pretty straight forward; however, because the data is retrieved dynamically every time the page is loaded, there’s a couple of tricks you need to apply to get the jQuery Mobile framework to do it’s magic.

The main page you’re greeted with is simply a glorified un-ordered list of programmes, with separator list items to distinguish the channels. I’m not going to go into the details of how you need to structure a page (see links at the end of this post) but here’s a snippet of the HTML:

1
2
3
4
5
6
7
8
<body>
    <ul id="channels" data-role="listview">
        <li data-role="list-divider">RTE One</li>
        <li><a href="#RTE-One-1">21:00: 9 O'Clock News</a></li>
        <li><a href="#RTE-One-2">21:35: Prime Time</a></li>
        <li data-role="list-divider">RTE Two</li>
        .. etc.
    </ul>

When the page loads, ul#channels is empty. The data is called via a jQuery GET, which gets over cross-domain restrictions by using YUI, thanks to the Cross-Domain AJAX mod. The relevant data is filtered out and formatted and each of the li‘s are built and inserted into #channels. At this point, if you look at the page in your browser, it’ll still look like an ordinary list – you need to tell jQuery to work it’s magic on the dynamically created data. In this instance it’s done as follows:

1
$("#channels").listview("refresh");

Once I had my list of programmes, I thought I may as well add the info for each program, seeing as I already had the data at my disposal. The route I decided to go down here was to create new ‘page’ div‘s for each program, each one having it’s own ID, then link to each of these pages from the li‘s. Again, the scope of building one of these pages is beyond this blog post and well documented elsewhere, but here’s a quick sample:

1
2
3
4
5
6
7
8
9
10
11
12
<div data-role="page" id="RTE-One-1" data-url="RTE-One-1">
    <div data-role="header">
        <h1>RTE one</h1>
    </div>
    <div data-role="content">
        <h2>9 O'Clock News: 21:00</h2>
        An update on the latest domestic and international events of the day.
    </div>
    <div data-role="footer">
        &copy; David Coen 2011
    </div>
</div>

This is simply added to the body using $('body').append(page); (where the variable page is a string of HTML such as the above). So, again here you need to tell jQuery Mobile that you’ve added a new page, so it can do it’s magic. This is achieved by the one simple line:

1
$('#RTE-One-1').page();

Hopefully this post will clear up a couple of things for anyone using jQuery Mobile with dynamically generated data. As I promised, here are some links of articles that helped me get a better understanding of the framework:

Full implementation code (UPDATE 2)

I was requested by @danny to post the full source code, seeing as the app is actually no longer available, so I’ve decided to put most of it here. I excluded some of the scrape JS (as indicated in the code comments) to prevent the app being re-used somewhere else.

So, first up, is the initial HTML page, with header and footer blocks, an empty content block and the JS and CSS includes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<html>
  <head>
    <title>What's on now</title>
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a1/jquery.mobile-1.0a1.min.css" />
    <script type="text/javascript" src="./jquery.min.js"></script>
    <script type="text/javascript" src="./jquery-mobile.min.js"></script>
    <script type="text/javascript" src="./whatson.js"></script>
  </head>
  <body>
    <div data-role="page" id="home">

      <div data-role="header">
        <h1>What's on now</h1>
      </div>

      <div data-role="content">
        <ul id="channels" data-role="listview">
        </ul>
      </div>

      <div data-role="footer" style="text-align: center;">
        <a href="http://www.drcoen.com">&copy; David Coen 2011</a>
      </div>

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

Next up is the javascript file, whatson.js in the above. Don’t forget, the $.ajax call has been overwritten by the Cross-Domain AJAX plug-in I mentioned earlier. Addtionally, I’ve used a few functions from php.js. to replicate this functionality in JS, namely str_replace, in_array and trim. I’ve excluded them here but they can be found in the php.js website.

Also, just to re-clarify, the page i was scraping had a list of channels and programs that were on now (prog1) and next (prog2).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
$(document).ready(function() {
  var cable_channels = [
    'RTE One',
    'RTE Two',
    'BBC One',
    // etc......
  ];
  $.mobile.pageLoading();
  $.ajax({
    url: // URL for the data
    type: 'GET',
    success: function(data) {
      html = $(data['responseText']);
      // for each channel scrapped
      $('td.listing-channel', html).each(function(){
        var channel = // code omitted
        var prog1_start, prog2_start, prog1, prog2, prog1_name, prog2_name;
        // if it's a channel I'm interested in
        if (in_array(channel, cable_channels))
        {
          // get the name, start time and description of the program currently being shown on the channel
          prog1_start = // start time of 1st program - code omitted
          prog1_name = // name of 1st program - code omitted
          prog1 = // description of 1st program - code omitted

          // do the same for the one on after it
          prog2_start = // start time of 2nd program - code omitted
          prog2_name = // name of 2nd program - code omitted
          prog2 = // description of 2nd program - code omitted

          // replace spaces with '-' for a valid #id
          var id = str_replace(' ', '-', channel);

          //create new block on the main page for our channel and it's 2 programs
          var li = '<li data-role="list-divider">' + channel + '</li>' +
            '<li><a href="#' + id + '-1">' + prog1_start + ': ' + prog1_name + '</a></li>' +
            '<li><a href="#' + id + '-2">' + prog2_start + ': ' + prog2_name + '</a></li>';
          $('#channels').append(li);

          // create a new page for the program description - clicking on the program in the <li> above will
          // bring you to this new description page
          var page = '<div data-role="page" id="'+id+'-1" data-url="'+id+'-1">' +
            '<div data-role="header">' +
              '<h1>' + channel + '</h1>' +
            '</div>' +
            '<div data-role="content">' +
              '<h2>' + prog1_name + ': ' + prog1_start + '</h2>' +
              prog1 +
            '</div>' +
            '<div data-role="footer" style="text-align: center;">' +
              '<a href="http://www.drcoen.com">&copy; David Coen 2011</a>' +
            '</div>';
          $('body').append(page);
          $('#'+id+'-1').page();

          // Do same again for 2nd program
          page = '<div data-role="page" id="'+id+'-2" data-url="'+id+'-2">' +
            '<div data-role="header">' +
              '<h1>' + channel + '</h1>' +
            '</div>' +
            '<div data-role="content">' +
              '<h2>' + prog2_name + ': ' + prog2_start + '</h2>' +
              prog2 +
            '</div>' +
            '<div data-role="footer" style="text-align: center;">' +
              '<a href="http://www.drcoen.com">&copy; David Coen 2011</a>' +
            '</div>';
          $('body').append(page);
          $('#'+id+'-2').page();
        }
      });
      $("#channels").listview("refresh");
      $.mobile.pageLoading(true); // kill the page loading modal
    }
  });
});

I realise this code could be alot cleaner, but the app was still in it’s early stages before I was asked to take it down, thus I haven’t spent time tidying it up. Hopefully there’s enough here to figure out how to do what you need!

Tags: jquery jquery mobile Query Mobile and Dynamic Data | david | 23rd May, 2011 at 20:34pm | No Comments

No Comments

Leave a reply

You must be logged in to post a comment.