Introduction to jQuery Mobile

Filed under: jQuery Mobile

comments (24) Views: 17,376

In the beginning the web was dull and lifeless. Image mouseover code was tens of lines long, and wasn't cross-browser. Then came jQuery which allowed developers to write beautiful JavaScript which worked everywhere. Then the jQuery team decided to develop jQuery UI which allowed developers to build rich, compelling web applications on top of jQuery. Then in late 2010 the jQuery team announced that they were working on jQuery Mobile (jQM), another framework specifically built with mobile phones in mind, providing UI components, data structuring, page transitions, and more. Lightweight, flexible, and built on the principles of progressive enhancement, jQuery Mobile runs on every platform out there from your Dad's old Startac, to the newest Android or iPhone. I'm kicking off a series of blog posts about jQMso if you're keen to learn, then make sure you keep checking in.

See a live jQuery Mobile Project at Goba.mobi.

The Basics of jQuery Mobile

As I mentioned earlier, jQM is based on the principles of progressive enhancement. What's that in layman's terms? It means that at the heart of your project, your code is all plain vanilla HTML. Bulleted lists, paragraph tags, and yes divs, images, anchor tags, and more. Then, the better your browser is at interpreting JavaScript and CSS, the more bells and whistles that you get. This ensures that old Blackberry phones will get it, as well as the newest Motorola Atrix. Let's take a look at an uber basic jQM page.

The first thing to note is that the doctype is HTML5. Easy to remember, and allows jQMto work it's magic. Next we see the 3 files we'll need at minimum. All three are hosted on jQuery's CDN. If you choose not to use their's I strongly suggest you use Google's or Microsoft's CDN files as it helps everyone. As we scan through the code you'll notice that there's nothing else really of note except for these strange "data-" attributes sprinkled throughout. That's a new feature in HTML5 allowing developers to pass structured data around the application. Consider it a simple tag specific database and you're right on the money. jQMmakes extensive use of custom data attributes to tell the engine how it should treat various parts of the page.

A Closer Look

Closer examination of the code shows us that there are 5 unique occurences of data-role. That mirrors the hierarchy of the page and results in the screenshots seen below.

  • data-role="page" - defines the current "page" being viewed by the user. When making AJAX page transitions, jQMpulls content from the DOM node "page" of the requested page and loads it into view.
  • data-role="header" - defines the head area of the page. Contains back buttons (when needed), and page titles
  • data-role="content" - the content portion of the page.
  • data-role="listview" - tells jQM to render this unordered list as a pretty table view, ala the iPhone.
  • data-role="list-divider" - tells jQM to render this specific list item as a list header.

jQuery Mobile Built-in Goodness

There's a few more things we need to point out, things that jQM does for "free". Notice that each of the normal list items has a link on it. jQM determines that if a list item has an anchor tag, it will automatically add an arrow icon >. Even nicer is that not only can you swap between a dozen or so built-in icons, but you can also design your own, and inject them into the framework with custom CSS.

To use custom icons, specify a data-icon value that has a unique name like myapp-email and the button plugin will generate a class by prefixing ui-icon- to the data-icon value and apply it to the button. You can then write a CSS rule that targets the ui-icon-myapp-email class to specify the icon background source. To maintain visual consistency, create a white icon 18x18 pixels saved as a PNG-8 with alpha transparency.

You should also note that when a table view (data-role="listview") has a data-inset attribute of true, jQM will round the corners of the first and last element. No intercession on your part is necessary. Add an element and jQM automatically calculates the first, and last, item in the list and rounds the appropriate corners. One final thing to point out in this basic view is page transitions. When linking between documents in the same domain, jQM will use beautiful transitions when moving back and forth.

The last thing I'd like to point out is jQM's ability to theme. Notice the data-theme="e" attribute on the last list item. It's now a member of the "e" theme which is a yellow tint. All of it's children would follow the yellow theme while it's siblings remain silver. Theming in jQM is simple if you remember the following color sets. It's also simple to add your own theme. I'll be writing a future blog post on doing just that.

  • The "a" theme is predominantly black
  • The "b" theme is predominantly blue
  • The "c" theme is predominantly grey/silver
  • The "d" theme is predominantly white
  • The "e" theme is predominantly yellow

If you're going to be attending cf.Objective() this May 12-14 in Minneapolis make sure to attend my session Using jQuery Mobile for your Next Web Application.

You can also download code samples and a slide deck from my talk "Using jQuery Mobile for your Next Web Application" that I gave at cfObjective in May, 2011.

Amazon logo

If this article was interesting, or helpful, or even wrong, please consider leaving a comment, or buying something from my wishlist. It's appreciated!

Related Posts


I did a mobile photo gallery with jQM a couple weeks again, and the biggest tip I can give to anyone who is going to be using jQM right now is just remember, it's still in alpha! I still managed to make a pretty good looking site with swipe detection/on orientation change fairly easily, but sometimes thing just don't work. Which to be fair, should be expected in an alpha release. Since I put that mobile site into production, there has been 2 updated releases to the CSS and JS. So the support is there, which is great.

Jeremy - February 08, 2011 03:41 pm

Great post! I need a good primer on jQM. Keep the info coming! Many thanks!

Steve - February 10, 2011 08:49 am

Just started today with jQuery Mobile and I am quite amazed at how easy it is to get started and what they give you for free is quite incredible. All of the page transitions and things like that all built-in is remarkable.

Tom - February 10, 2011 11:40 am

Great Article!!! I just startet a few Days ago to use jQuery mobile with ColdFusion AND i love it!

Reinhard Jung - February 13, 2011 10:39 pm

Hi, You have an amazing tutorial, its really helpful. Thanks again. My quick question would be I was unable to use jquery validation with jquery mobile form. Have you tried it or can check if it works for you? That would be totally helpful to not do custom validations in jquery.

Sam - June 10, 2011 11:14 am

Thanks for the kind words Sam. There's no reason you shouldn't be able to use a jQuery validation plugin. My guess is that you're not taking the proper jQM approach. There's a way that you can call plugin code ONLY on the pages which require it. Have a look at this article I wrote a while back. It covers how to run code only on specific pages. I think it'll solve your problem.

andy matthews - June 11, 2011 01:41 pm

I'm building a jquery mobile website right now myself and have stumbled upon an interesting problem that i can't for the life of me figure out how to solve. My app is about 5 pages long. On each page is a webform. The webform is the same exact form on every page. so I have index.html, page2.html, page3.html, page4.html. I have a script that does some basic form validation and then submits the values of the form via ajax. When i load index.html, everything runs great. My form validation works and i can submit the form and the data is delivered. Problems occur when i click page2.html, so now my url looks like index.html#page2.html. When i submit the form on this page, it actually performs the form validation across all of the forms so really i can not submit the form on any interior page. Some ideas to solve the problem i thought off were: 1. using JS and only submit the form that is in view. 2. disable all form that are not in view so only one form can submitted at a time. 3. write the form in javascript and have it output the html, then load and unload the form each time a page transition happens? I've $("form").submit() { ... } and this doesn't seem to work, i can't seem to get it to submit the form via this method. Any suggestions?

Robbiegod - June 24, 2011 08:16 pm

Robbie...

If you're saying that the form is identical, and that you only have 5 pages, you might consider putting all the "pages" into one actual HTML page (index.html). There are two main ways to load content with jQuery Mobile. You can have an actual HTML page and call it using it's file name:

%lt;a href="page2.html"%gt;Load page two%lt;/a%gt;

Or you can load the contents of a div:

%lt;a href="#page2"%gt;Load page two%lt;/a%gt;

Either way jQuery Mobile will replace the current page content with the content of the new page. The benefit of doing it this way is that you only ever have one form. It's worth a shot.

andy matthews - June 25, 2011 11:19 am

Thanks for the reply. Is there a way I can turn off AJAX loading my pages but still apply the cool transitions? If I can get my app to actually do a full page refresh, i think i can work around the problem. Currently, I am using links like this: page 2 and also i am using page 3 to load a page that pulls in some data from an external php page. The problem i see is that if i have a form on index.html and a form on page2.html that are identical, when i submit the form, it actually runs my form validation across both forms -- so really, both forms are still in view. This is causing mucho headaches and at the moment i've removed the form from my internal pages and replaced it with a button to go back to the homepage, not exactly what i want to do though because the form is the heart of the app. Trying to get alot of signups. Any idea how i might disable all forms except the one that is in view? It sounds from your reply that this should just work the way i have it now, but sadly, it does not. Thanks again andy. If you have time and if you want to see this interesting problem in action, I will put together a demo area. This might be a bug in jquery mobile. I'm not sure.

Robbiegod - June 25, 2011 02:49 pm

You're in luck. There is actually a global config option to disable AJAX loading:

$.mobile.ajaxEnabled (boolean, default: true):

andy matthews - June 25, 2011 10:19 pm

But then can i apply the transition eventhough i've turned off ajax? thanks again!

Robbiegod - June 25, 2011 10:35 pm

well, i kind of got it to work. The solution I found was in each page where i had the form i had to give all of the form elements unique IDs. So homepage form had a FirstName field with ID FirstName1. On page2 I had to make it have an ID of FirstName2. This way when i submitted my forms and used my ajax script it would only submit the values from "this" form i am submitting. If all of the form fields are identical, then when you submit the form that values get confused. So technically when a new page is view and you need to do form validation the previous form might be off screen but its still there. So the next hurdle is I have homepage and page2. When i submit the form on the homepage my onsuccess works great. It replaces the form with my thank you message. But, when i submit the form and do it on an internal page, it doesnt replace the form. Any ideas why? Here's that snippet of code i am using: $.ajax({ type: "POST", url: "process-mail.php", data: dataString, success: function() { $('#odForm').html("

"); $('#SuccessMsg').html("

Thank you

") .append("

You will receive an email with details

").fadeIn('normal'); } All pages have the div ID #odForm. Maybe i need to make that unique too? Perhaps when i submit the form, its changing the div on the homepage which is out of view?

Robbiegod - June 27, 2011 11:34 am

Actually, you could probably have gone even easier and just given each form a unique ID. Then you could call the submit method on the specific form and not be bothered by different form field IDs.

andy matthews - June 27, 2011 07:17 pm

I had actually tried that. I had form id=form1 and form id=form2, but since the forms shared the same field names it didn't matter if i was submitting form1 or form2, it was still validating both fields. The best way i could find to make it work is by making everything unique, kinda sucked because i was hoping to just one set of html for the form and one set of html for the validation. I fought with it for a week. I think in theory it sounds like if each form had a unique ID and you have a trigger that selects just that ID to submit, it sounds like there should be any conflict, but there was. You can try it, but be sure to include some form validation, that is where it screws up.

Robbiegod - June 27, 2011 07:22 pm

Sounds like the targeting on your field validation wasn't specific enough. Are you familiar with the notion of "context" in jQuery?

Given a form with an id of "registration", and field names of firstname and lastname, you could uniquely reference the firstname field in "the context" of the "registration" form like so:

$('#firstname', '#registration').val();
$('#lasttname', '#registration').val();

Then, even if there are other input fields on the page with the same id (bad idea anyway right?), you'll always get the right one.

andy matthews - June 27, 2011 07:27 pm

interesting, i did not know that. See that ya learn something everyday. At least with your solution i could have the same form with different IDs and then just unique scripts per page -- so that might be a good way to go. :) Thanks for the tip!

Robbiegod - June 27, 2011 07:35 pm

Well, assuming that all of the forms have the same fields, and the same validation routines, you shouldn't need multiple code. You should be able to pass the current page, then get the form ON that page using the same contextual selector.

$('form', $currentPage).validate(); // pseudo-code
where $currentPage is a jQuery variable containing a reference to the current page.

andy matthews - June 27, 2011 07:48 pm

Hi, You have an amazing tutorial, its really helpful. My quick question would be I was unable to get the RSS content of any website to mobile jquery.I have tried it but couldn't find the answer. Have you tried it or can check if it works for you?

cognostek - July 06, 2011 12:12 am

Hey cognostek...

Most likely the problem is that you're trying to load an RSS from another site. Browsers don't allow that as it violates their cross domain policy. You can get around it though if the site hosting the RSS feed allows for JSONp requests. If the site does allow for that then you can use jQuery's built in getJSON method to retrieve the data:
http://api.jquery.com/jQuery.getJSON/

If they do not, then your only other alternative is to use a proxy file. This is a simple (or not so simple) server-side script written in ColdFusion, PHP, ASP (or any other server-side language) that you call from your JavaScript, which in turn makes an http request to the remote site and retrieves the data. So it would look something like this:

Your page --> script on your site --> CNN.com --> script on your site --> Your page

andy matthews - July 06, 2011 06:43 am

hi, Thanks for the reply..Your answer was useful for me..I have received RSS content of my website to mobile jquery through javascript but now the link in the rss page, opens in a new original website location. Actually this is not the thing i want. The link in the rss page should open in the original present mobile page. Is there any method to do this.. below is the html code... Untitled Document $(document).ready(function () { $('#test').rssfeed('http://feeds.reuters.com/reuters/oddlyEnoughNews', { limit: 5 }); });

This is zrssfeed.js code, // JavaScript Document (function($){ $.fn.rssfeed=function(url,options,fn) { var defaults={limit:20,header:true,titletag:'h4',date:true,content:true,snippet:true,showerror:true,errormsg:'',key:null,ssl:false,linktarget:'_self'}; var options=$.extend(defaults,options); return this.each(function(i,e) { var $e=$(e); var s=''; if(options.ssl)s='s'; if(!$e.hasClass('rssFeed'))$e.addClass('rssFeed'); if(url==null)return false; var api="http"+s+"://ajax.googleapis.com/ajax/services/feed/load?v=1.0&callback=?&q="+encodeURIComponent(url); if(options.limit!=null)api+="&num="+options.limit; if(options.key!=null)api+="&key="+options.key; api+="&output=json_xml" $.getJSON(api,function(data){if(data.responseStatus==200) { _process(e,data.responseData,options); if($.isFunction(fn))fn.call(this,$e); } else { if(options.showerror) if(options.errormsg!='') { var msg=options.errormsg; } else { var msg=data.responseDetails; }; $(e).html('

'+msg+'

');};});});}; var _process=function(e,data,options) { var feeds=data.feed;if(!feeds){return false; } var html=''; var row='odd'; var xml=getXMLDocument(data.xmlString); var xmlEntries=xml.getElementsByTagName('item'); if(options.header) html+=''; html+='
'+'
    '; for(var i=0;i'+'<'+options.titletag+'>'+entry.title+'' if(options.date)html+='
    '+pubDate+'
    ' if(options.content) { if(options.snippet&&entry.contentSnippet!='') { var content=entry.contentSnippet; } else{var content=entry.content; } html+='

    '+content+'

    '} if(xmlEntries.length>0) { var xmlMedia=xmlEntries[i].getElementsByTagName('enclosure'); if(xmlMedia.length>0) { html+='
    Media files
      ' for(var m=0;m'+xmlUrl.split('/').pop()+' ('+xmlType+', '+formatFilesize(xmlSize)+')'; } html+='
    ' } html+=''; } if(row=='odd') { row='even'; } else{ row='odd'; } } html+='
'+'
' $(e).html(html); }; function formatFilesize(bytes) { var s=['bytes','kb','MB','GB','TB','PB']; var e=Math.floor(Math.log(bytes)/Math.log(1024)); return(bytes/Math.pow(1024,Math.floor(e))).toFixed(2)+" "+s[e]; } function getXMLDocument(string) { var browser=navigator.appName;var xml; if(browser=='Microsoft Internet Explorer') { xml=new ActiveXObject('Microsoft.XMLDOM'); xml.async='false' xml.loadXML(string); } else{ xml=(new DOMParser()).parseFromString(string,'text/xml'); } return xml; } })(jQuery);

cognosek - July 07, 2011 02:55 am

Hi Andy Matthews, very nice tutorial. I am a Brazilian developer. I wonder if I can translate the tutorial and post it on my blog? Keeping the credits, of course. Thanks

Daniel Lemes - March 04, 2012 12:32 pm

Daniel...that sounds awesome. You're welcome to translate it. I don't speak Portuguese but when you're done please post the link to your article, and I'll also mention it on Twitter.

andy matthews - March 04, 2012 12:57 pm

Daniel Lemes translated this article into Portuguese.

http://www.dlemes.com/blog/2012/03/10/introducao-ao-jquery-mobile/

Great job Daniel!

andy matthews - March 10, 2012 12:34 pm

great tutorial. specially for handheld lovers.

Ahmed - May 02, 2012 04:00 am