Fedex’s techie blog Yet Another Tech Blog

6Sep/110

Extremely fast mobile integration with jQuery Mobile

Yesterday in twitter I've noticed that the owner of one of the sites I usually visit said that he wanted to make the mobile version of his site but the estimated cost that someone gave him was too high. Today he and the dev of the site opened an API for us to make our own mobile version. As soon as I saw the site was running with a drupal site I knew that the integration was going to be a peace of cake as this great CMS can expose everything to a JSON rest service.

Getting started

We need to know what is the expected JSON to request. Here the site's dev exposed the API. As you can see the objects are really simple so we are going to implement the "Recents links" list with a little detail.
Let's start with the list:

<html>
    <head>
        <title>
            Fierita Links Mobile
        </title>
        <link href="http://code.jquery.com/mobile/latest/jquery.mobile.min.css" rel="stylesheet" type="text/css" />
        <script type="text/javascript" src="http://code.jquery.com/jquery-1.6.2.min.js"></script>
        <script type="text/javascript" src="http://code.jquery.com/mobile/latest/jquery.mobile.min.js"></script>
        <script type="text/javascript">
            $(document).ready(function () {
                $.getJSON('http://links.fierita.com/api/vistas/nuevos?callback=?', function (data) {
                    $(data.results).each(function (index, result) {
                        $('#ulNoticias').append('<li><a href="http://links.fierita.com/node/' + result.nid + '">' + result.title + '</a></li>');
                    });
                    $('#ulNoticias').listview('refresh');
                });
            });
        </script>
    </head>
    <body>
        <div data-role="page"> 
	        <div data-role="header"><h1>Fierita Links</h1></div> 
	        <div data-role="content">        
                <ul data-role="listview" id="ulNoticias" data-theme="g">
                    
                </ul>
            </div> 
	        <div data-role="footer">created by <a href="http://www.spiritconsulting.com.ar/">Spirit Consulting</a></div> 
        </div> 
    </body>
</html>

This snippet is really simple we don't even have to bother about hosting our own libraries, just an html and we are all set, it also created an abstraction layer that you don't see that often.
What we are doing here is creating a simple mobile page as we saw before and filling a list with the JSON parsed from the service. One thing to notice is the ?callback=? to the service URL, it tells the jQuery library that the request we are doing is going to be a JSONP one as it a cross domain call, luckily for us Drupal support this kind of requests and send us back the propper JSONP response.

Now we are going to add the details view as our current application open the full desktop site when we select an item from the list.

<html>
    <head>
        <title>
            Fierita Links Mobile
        </title>
        <meta name="viewport" content="width=device-width, initial-scale=1"> 
        <link href="http://code.jquery.com/mobile/latest/jquery.mobile.min.css" rel="stylesheet" type="text/css" />
        <script type="text/javascript" src="http://code.jquery.com/jquery-1.6.2.min.js"></script>
        <script type="text/javascript" src="http://code.jquery.com/mobile/latest/jquery.mobile.min.js"></script>
        <script type="text/javascript">
            var aticuloId = -1;

            $(document).ready(function () {
                $.getJSON('http://links.fierita.com/api/vistas/nuevos?callback=?', function (data) {
                    $(data.results).each(function (index, result) {
                        $('#ulNoticias').append('<li><a class="viewItem" href="#details" data-nid="' + result.nid + '">' + result.title + '</a></li>')
                    });
                    $('#ulNoticias').listview('refresh');
                });
                $('.viewItem').live('click', function () {
                    $.mobile.pageLoading();
                    aticuloId = $(this).data('nid');
                });
            });
            $('#home').live('pageshow', function (event, ui) {
                if ($(this).find('#ulNoticias').children().length <= 0) {
                    $(this).find('#ulNoticias').html($('#ulNoticias').html());
                }
            });

            $('#details').live('pagebeforehide', function (event, ui) {
                $('#detailsThumb').attr('src', '');
                $('#detailsBody').html('');
                $('#detailsTitle').html('');
                $('#detailsLink').attr('href', '#');            
            });

            $('#details').live('pageshow', function (event, ui) {
                $.getJSON('http://links.fierita.com/api/enlace/' + aticuloId + '?callback=?', function (data) {
                    $('#detailsThumb').attr('src', data.thumb);
                    $('#detailsBody').html(data.body);
                    $('#detailsTitle').html(data.title);
                    $('#detailsLink').attr('href', data.link);
                    $.mobile.pageLoading(true);
                });
            });
        </script>
    </head>
    <body>
        <div data-role="page" id="home"> 
	        <div data-role="header"><h1>Fierita Links</h1></div> 
	        <div data-role="content">        
                <ul data-role="listview" id="ulNoticias" data-theme="g">
                    
                </ul>
            </div> 
	        <div data-role="footer">created by <a href="http://www.spiritconsulting.com.ar/">Spirit Consulting</a></div> 
        </div> 
        
        <div data-role="page" id="details" data-add-back-btn="true"> 
	        <div data-role="header"><h1 id="detailsTitle"></h1></div> 
	        <div data-role="content">        
                <img id="detailsThumb" style="width:100%; max-width: 256px" src="" />
                <div id="detailsBody"></div>
                <a id="detailsLink" href="">Enlace</a>
            </div> 
	        <div data-role="footer">created by <a href="http://www.spiritconsulting.com.ar/">Spirit Consulting</a></div> 
        </div> 

    </body>
</html>

Ok this snippet is a bit longer than the last one but is equally simple. The first thing we notice is that the link is modified to point to our div (the mobile page container called 'details') and there is a new attribute called data-nid that is going to hold the value of the drupal's node. We are using these technique as is the most "elegant" way I've found to pass parameters to a new page contained in a multi page document.

The lines of code that make the param magic are:

$('.viewItem').live('click', function () {
	$.mobile.pageLoading();
	aticuloId = $(this).data('nid');
});

That takes the nid value of the link and puts it in a global variable accesible to the loaded page, and

            $('#details').live('pageshow', function (event, ui) {
                $.getJSON('http://links.fierita.com/api/enlace/' + aticuloId + '?callback=?', function (data) {
                    $('#detailsThumb').attr('src', data.thumb);
                    $('#detailsBody').html(data.body);
                    $('#detailsTitle').html(data.title);
                    $('#detailsLink').attr('href', data.link);
                    $.mobile.pageLoading(true);
                });
            });

That fills the new page fields with another call to the service requesting the detailed view. Off course you may agree with me that the design created is awful but it's a fast integration! We will have time later to improve our app.

The last bits of code that may need some explanation are:

            $('#home').live('pageshow', function (event, ui) {
                if ($(this).find('#ulNoticias').children().length <= 0) {
                    $(this).find('#ulNoticias').html($('#ulNoticias').html());
                }
            });

I've found (and I don't know if these is a behaviour that you can prevent) that when you hit the back button on the generated detail page it creates another version of the dom objects, I mean that it will be 2 elements called 'ulNoticias'. So whenever we go back to the home page the list will remain empty as it will display the newly generated element. To overcome that and don't make another ajax request we just search for the original element in the dom and fill the new one with it's html code. As a side note it makes me wonder how the memory management will function if I go back and fourth and jQM starts creating tons of copy of my dom elemnts.

Any questions? Any thoughts? Be creative at the comments! You can find an online version of this code here. In the meanwhile I may improve this version of the code for being able to display more data from the site.

No related content found.

Comments (0) Trackbacks (0)

No comments yet.


Leave a comment

No trackbacks yet.