Building Mobile Apps with WebMatrix and jQuery Mobile

jquery Mobile was launched just a month or so ago, and is designed to make it as easy to build JavaScript-enabled web applications for mobile phones as for the desktop browser. Still in Alpha, the library has a way to go, but it already offers a rather interesting experience when used as part of a mobile phone targeted web application. Here's a first look at how to use jQuery Mobile with WebMatrix to build a mobile web application.

Before I start, here's some stuff you should know about jQuery Mobile. The jquery Mobile library works on top of the core jQuery library. In essence, it is an alternative jQuery UI library which in the Alpha release applies a very iOS (iPhone, iPad) looking styling to elements. It also makes use of CSS3 and HTML 5 custom data attributes. Consequently, to get the full effect, you need to use a browser which has reasonable support for HTML 5. That effectively excludes Internet Explorer 8 and below. The jQuery team have produced a chart showing how much support they plan to offer for each browser here, but if you want to test your application in a browser, you should use FireFox, Safari, Google Chrome or Opera. Alternatively, you can use an emulator such as iBBDemo2, which is an Adobe Air based application. Finally, you could use IE9, which is in Beta at the moment (and doesn't seem to manage rounded corners that well). IE8 does have one handy use - it can be used to debug your site. Any jQuery Mobile application is designed to degrade in a browser that doesn't support HTML 5 or CSS 3, which means that compilation and runtime error messages are clearly visible in IE8.

The sample site I have built, and which is available for download at the end of the article is extremely simple. It makes use of a SQL CE 4.0 version of the Northwind database. It doesn't do much - it lists product categories and allows you to drill down to details on specific products. I haven't added any data writing capabilities yet. Here's how the main page looks in the emulator:

The jQuery Mobile library consists of a JavaScript file which makes use of the jQuery Core, and a style sheet together with some images. I downloaded the zip containing the library from the jquery Mobile site and placed jquery.mobile-1.0a2.min.js in a newly created folder which I called Scripts, along with the latest version of the jquery Core library - jquery-1.4.4.min.js. I also created a folder called Styles, in which I placed the jquery.mobile-1.0a2.min.css file that came with the download. To the Styles folder, I also added the images which came with the download in a folder called images. I wouldn't normally add images to a style sheet folder, but this saved me having to edit the css file to point to images in a new location.

As you can see from the image, I also created a folder called Shared and added a new CSHTML file to that called _Layout.cshtml. This is the Layout page, which contains the references to jQuery and the style sheets:

<!DOCTYPE html>

<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>@Page.Title</title>
        <link rel="stylesheet" href="@Href("~/Styles/jquery.mobile-1.0a2.min.css")" type="text/css" />

        <script src="@Href("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
        <script src="@Href("~/Scripts/jquery.mobile-1.0a2.min.js")" type="text/javascript"></script>
    </head>
    <body>
        <div data-role="page" data-theme="c"> 
            <div data-role="header">
                <h1>@Page.Header</h1>
            </div>
            @RenderBody()
        </div>
    </body>
</html>

The first thing to point out is that since jQuery Mobile likes HTML 5, you need the HTML 5 doctype:

<!DOCTYPE html>

Razor uses this doctype by default, which makes Web Pages an ideal platform to develop jQuery Mobile sites with. The same is true of ASP.NET MVC 3 if you are using the Razor View Engine, or another View Engine which supports HTML 5. The default doctype for Web Forms is still XHTML 1.1, so if you wanted to create a Web Forms app, or an MVC app that makes use of the Web Forms View Engine, you need to amend the doctype.

The content is housed in a div with two attributes: data-role and data-theme. When page is specified as the value for the data-role attribute you are telling jQuery that the content is a View. There are a number of themes (styles) built into jQuery Mobile. These are specified via the data-theme attribute. I have chosen the one labeled as "c". The first image shows a bar across the top of the View containing "Categories". This styling is created by applying "header" as a value to the data-role attribute. I have designed it so that the header is part of the Layout, but dynamic so that I can set it from each of the individual pages.

Next I added a new CSHTML file called Default.cshtml. This is the "home page" of my mobile site:

@{
    Layout = "~/Shared/_Layout.cshtml";
    Page.Title = "Home";
    Page.Header = "Categories";
    var db = Database.Open("Northwind40");
    var sql = @"SELECT [Category ID] AS ID, [Category Name] As Name 
              FROM Categories ORDER BY [Category Name]";
    var data = db.Query(sql);
}
 <div data-role="content">
    <ul data-role="listview" data-inset="true" data-theme="d">
        @foreach(var item in data){
            <li><a href="/Category/@item.ID">@item.Name</a></li>
        }
    </ul>
</div>

The code block at the top of the page defines the layout page, and sets the title and the header content. Then it queries the database for the list of Categories which it returns in alphabetical order. The Categories are displayed as list items within an unordered list whose data-role is defined as listview. The list view is placed inside an element which has been given the data-role="content" attribute, which separates it from headers and footers. I have also applied data-inset="true" to the list so that the list acquires some borders and margins. The result is the same as you see in the first image. You can see that any list item which contains a hyperlink will automatically get an arrow pointing to the right. That's applied by jQuery itself. At the moment, there's nothing for the hyperlink to point to so the next step is to add a page called Category.cshtml:

@{
    Layout = "~/Shared/_Layout.cshtml";
    Page.Title = "Products";
    Page.Header = "Products";
    if(UrlData[0].IsEmpty()){
        Response.Redirect("~/");
    }
    var db = Database.Open("Northwind40");
    var sql = @"SELECT [Product ID] AS ID, [Product Name] As Name FROM Products 
                WHERE [Category ID] = @0 ORDER BY [Product Name]";
    var category = UrlData[0];
    var data = db.Query(sql, category);
    var firstLetter = "";
}
<div data-role="content">
    <ul data-role="listview" data-inset="true" data-theme="d" data-dividertheme="b">
    @foreach(var item in data){
        if(item.Name.Substring(0,1) != firstLetter){
            <li data-role="list-divider">@item.Name.Substring(0,1).ToUpper()</li>
            firstLetter = item.Name.Substring(0,1);
        }
        <li><a href="/Product/@item.ID">@item.Name</a></li>
    }
    </ul>
</div

This page detects which category was selected from the Url. If none was, the user is redirected back to the home page. Otherwise the products belonging to the selected category are taken from the database and displayed in alphabetical order. There's also a variable called firstLetter which is set to an empty string. That's used to act as a seed value for the alphabetical listing. You can see the unordered list being used as in the previous page, but this time a new data-role is introduced: data-role="list-divider". This is not an item in the list itself. Instead, I have chosen to categorise the result by the first letter in the product name. You can see how this appears in the next image, which also shows the preview in the desktop version of Safari:

As you can see, each letter is displayed in a blue background list divider, whereas the actual data items are displayed with the now familiar right arrow. The logic which causes the alphabet to display goes as follows:

If the first letter of the current item in the foreach loop (obtained using Substring) is not the same as the value of the firstLetter variable, print the first letter of the current item. then set the value if firstLetter to the value of the first letter of the current item. This prevents the condition returning true if the next item begins with the same letter. When the next item in the result starts with a different letter, the condition returns false, so its first letter is printed.

Apart from seeing how the View is formatted in Safari, you also get an indication of how one View transitions to another, as the experience emulates that of the iPhone for example. New pages are retrieved via AJAX calls, and the resulting HTML is appended to the current DOM by jQuery Mobile. Then an effect is applied to the existing View so that it slides to the left by default, with the new View sliding in to replace it. Other transition effects can be achieved through the data-transition attribute which you would apply to the link itself eg:

<li><a href="/Product/@item.ID" data-transition="flip">@item.Name</a></li>

Options include slideup, slidedown, fade, pop and flip.

The final page shows the details for any selected product:

@{
    Layout = "~/Shared/_Layout.cshtml";
    Page.Title = "Products";
    Page.Header = "Product details";
    if(UrlData[0].IsEmpty()){
        Response.Redirect("~/");
    }
    var product = UrlData[0];
    var db = Database.Open("Northwind40");
    var sql = @"SELECT Products.[Product Name] AS Name, 
                Categories.[Category Name] AS Category, 
                Suppliers.[Company Name] AS Supplier, 
                Products.[Quantity Per Unit]  AS Quantity,
                Products.[Unit Price] AS Price, 
                Products.[Units In Stock] AS InStock, 
                Products.[Units On Order] AS OnOrder
                FROM Products 
                INNER JOIN
                Categories ON Products.[Category ID] = Categories.[Category ID] 
                INNER JOIN
                Suppliers ON Products.[Supplier ID] = Suppliers.[Supplier ID]
                WHERE Products.[Product ID] = @0";
    
    var item = db.QuerySingle(sql, product);
}

<div data-role="content" data-theme="d">
    <ul data-role="listview" data-inset="true" data-theme="d" data-dividertheme="b">
        <li data-role="list-divider">@item.Name</li>
        <li>Supplier: @item.Supplier</li>
        <li>Category: @item.Category</li>
        <li>Quantity per unit: @item.Quantity</li>
        <li>Units In Stock: @item.InStock</li>
        <li>Units On Order: @item.OnOrder</li>
    </ul>
</div>    

You should be getting the gist by now, and it shouldn't be too much of a surprise to see that the code above renders like the image below:

jQuery Mobile still has a way to go. Support across browsers is a little patchy, but even in its currrent Alpha state, it provides a really powerful UI framework for building cross-platform mobile web sites that look and feel very familiar to mobile app users. Windows 7 users will be a little disappointed with the result because of the lack of support for HTML 5 in IE 8, but they can be persuaded to download and use Opera Mobile until IE 9 makes an appearance. There will be a lot more work done to jQuery Mobile before its full release, which seems to be slated for early 2011.

You can dowload the

7 Comments

Saturday, March 5, 2011 2:58 AM - Sharbel

Good intro, thank-you. The data access at the top of the View makes me cringe a bit though! :)

Saturday, March 5, 2011 11:06 AM - Mike

@Sharbel,

It's not a "View". It's a Web Pages file.

Thursday, March 22, 2012 3:32 PM - Chris

Great article. Thank you! A quick question- can you still use _PageStart.cshtml in lieu of setting the _layoutcshtml page on each content page?

Cheers!

Tuesday, August 7, 2012 10:36 PM - Ellory

Thanks for your article. I wonder if you have tried creating this app as a hybrid app with PhoneGap. Have you used PhoneGap with WebMatrix and JQM? If so, can you provide some details as how you went about it, testing it, and deploying to the appstores? Is there even such thing for WebMatrix?

Wednesday, August 8, 2012 7:42 AM - Mike

@Ellory,

No - I haven't used PhoneGap at all.

Friday, September 7, 2012 12:13 AM - Les Mc

Great article. A question: what is going on behind the scenes in terms of a connection string? Is there an implied web.config file that is managing the connection to the database Northwind40?

Thanks in advance.

Friday, September 7, 2012 5:53 AM - Mike

@Les

The Web Pages framework looks for a database file in App_Data with a file name that matches the string passed in to the Database.Open method. If it can't find one, it looks for a connection string in the web.config file that has the same name.
Add your comment

If you have any comments to make about this article, please use this form to do so. Make sure that your comment relates specifically to the article above. More general comments can be posted through the form on the Contact page.

Please note, all comments are moderated, and some may not be published. The kind of things that will ensure your comment is deleted without ever seeing the light of day are as follows:

  • Not relevant to the article
  • Gratuitous links to your own site or product
  • Anything abusive or libellous
  • Spam
  • Anything in a language I don't understand including gibberish.

I do not pass email addresses on to spammers, so a valid one will assist me in responding to you personally if required.

Recent Comments

Bino 11/27/2014 7:05 PM
In response to MVC 5 with EF 6 in Visual Basic - Async and Stored Procedures with the Entity Framework
Copy +...

Manas 11/27/2014 5:30 AM
In response to Scheduled Tasks In ASP.NET With Quartz.Net
Hi Mike, Thank you for awesome article. My concern is it might impact website if we use or is...

priya 11/26/2014 6:50 PM
In response to Create PDFs in ASP.NET - getting started with iTextSharp
very nice.....its save my time...

ransems 11/24/2014 12:29 AM
In response to Adding A Controller
Love the article. I dislike that the world thinks c# articles are the way to go. Love the VB, keep...

Gautam 11/20/2014 8:01 AM
In response to I'm Writing A Book On WebMatrix
Hello Mike, I read your book, loved it! However, I have a few request/suggestions: 1) an example...

Bret Dev 11/19/2014 8:39 PM
In response to The Difference Between @Helpers and @Functions In WebMatrix
Excellent post! One concern - where can you place global @Functions code within an MVC project to Is...

Rob Farquharson 11/19/2014 4:28 PM
In response to iTextSharp - Links and Bookmarks
How can I place text at an absolute position on the page? Also, how can I rotate text?...

Andy 11/17/2014 8:08 PM
In response to MVC 5 with EF 6 in Visual Basic - Sorting, Filtering and Paging
Hello I'm testing your sorting instructions above. This is great and I was able to get it to work...

Gautam 11/17/2014 5:51 PM
In response to WebMatrix - Database Helpers for IN Clauses
Hi Mike, I am very new to programming: In the above example if I want to use a delete button the...

donramon 11/17/2014 3:22 PM
In response to Entity Framework 6 Recipe - Alphabetical Paging In ASP.NET MVC
Congratulations on your new website look and the excellent articles. Thank you!...