Quick jQuery Mobile Tutorial by Comparison

Here’s a quick tutorial on jQuery Mobile. We’ll start with a standard HTML file, then add the jQuery elements in. Code and comparisons are provided. Just like the official jQuery documentation, we will be using div instead of the newer HTML5 semantic elements like header and footer. You can use the HTML5 elements, but remember to use HTML5 shiv if you want to support older browsers.

We start with a standard HTML with a header, menu, list, form and footer. It looks like this.

standard-HTMLThe HTML code is

<!DOCTYPE html>
<html>
<head>
</head>
<body>
	<div id="page">
		<div id="header">
			<h1>Header</h1>

			<div id="navbar">
				<ul>
					<li><a href="#">Menu 1</a></li>
					<li><a href="#">Menu 2</a></li>
				</ul>
			</div>
		</div>

		<div id="content">
			<p>Paragraph...</p>

			<ul id="listview">
				<li id="list-divider">List Divider</li>
				<li><a href="#">List Item 1</a></li>
				<li><a href="#">List Item 2</a></li>
				<li><a href="#">List Item 3</a></li>
			</ul>

			<form>
				<fieldset>
					<legend>Form Legend</legend>

					<div>
						<label for="input1">Input 1</label>
						<input id="input1" />
					</div>

					<div>
						<label for="input2">Input 2</label>
						<input id="input2" />
					</div>

					<div>
						<label for="toggle">Toggle</label>
						<select id="toggle">
							<option value="off">Off</option>
							<option value="on">On</option>
						</select>
					</div>

					<div>
						<input id="checkbox" type="checkbox" />
						<label for="checkbox">Checkbox</label>
					</div>

					<div>
						<input type="submit" value="Submit" />
					</div>
				</fieldset>
			</form>
		</div>

		<div id="footer">
			<h4>
				Footer
			</h4>
		</div>
	</div>
</body>
</html>

Nothing special here so far. Now we add jQuery Mobile in. First we add the jQuery Mobile JavaScript and CSS in the head. The viewport meta tag is needed so mobile browsers don’t display the page zoomed out.

<head>
	<meta name="viewport" content="width=device-width, initial-scale=1" />

	<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/jquery.mobile/1.2.0/jquery.mobile-1.2.0.min.css" />
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
	<script src="https://ajax.aspnetcdn.com/ajax/jquery.mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script>
</head>

Next we add the HTML5 data attributes in. These attributes are used by jQuery Mobile for markup-based initialization and configuration of widgets. We add it in the page, header, navbar, content, list, form, and footer. Here are the difference between the original HTML and the HTML with jQuery.

origin-HTML-and-html-with-jquery Our page now looks like this. new-page The code is now.

<!DOCTYPE html>
<html>
<head>
	<meta name="viewport" content="width=device-width, initial-scale=1" />

	<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/jquery.mobile/1.2.0/jquery.mobile-1.2.0.min.css" />
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
	<script src="https://ajax.aspnetcdn.com/ajax/jquery.mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script>
</head>
<body>
	<div data-role="page">
		<div data-role="header">
			<h1>Header</h1>

			<div data-role="navbar">
				<ul>
					<li><a href="#">Menu 1</a></li>
					<li><a href="#">Menu 2</a></li>
				</ul>
			</div>
		</div>

		<div data-role="content">
			<p>Paragraph...</p>

			<ul data-role="listview">
				<li data-role="list-divider">List Divider</li>
				<li><a href="#">List Item 1</a></li>
				<li><a href="#">List Item 2</a></li>
				<li><a href="#">List Item 3</a></li>
			</ul>

			<form>
				<fieldset>
					<legend>Form Legend</legend>

					<div data-role="fieldcontain">
						<label for="input1">Input 1</label>
						<input id="input1" />
					</div>

					<div data-role="fieldcontain">
						<label for="input2">Input 2</label>
						<input id="input2" />
					</div>

					<div data-role="fieldcontain">
						<label for="toggle">Toggle</label>
						<select id="toggle" data-role="slider">
							<option value="off">Off</option>
							<option value="on">On</option>
						</select>
					</div>

					<div data-role="fieldcontain">
						<input id="checkbox" type="checkbox" />
						<label for="checkbox">Checkbox</label>
					</div>

					<div>
						<input type="submit" value="Submit" />
					</div>
				</fieldset>
			</form>
		</div>

		<div data-role="footer">
			<h4>
				Footer
			</h4>
		</div>
	</div>
</body>
</html>

Nice, just the addition of a few data attributes and we have a nicely formatted mobile page. Now let’s add a few more data attributes, to make our page a little fancier before we wrap up. Let’s add some data-transition, data-inset, data-icon, and data-position attributes. The differences are difference The page now looks like: page-now-2 And the final code looks like:

<!DOCTYPE html>
<html>
<head>
	<meta name="viewport" content="width=device-width, initial-scale=1" />

	<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/jquery.mobile/1.2.0/jquery.mobile-1.2.0.min.css" />
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
	<script src="https://ajax.aspnetcdn.com/ajax/jquery.mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script>
</head>
<body>
	<div data-role="page">
		<div data-role="header">
			<h1>Header</h1>

			<div data-role="navbar">
				<ul>
					<li><a href="#" data-transition="slide" data-icon="home">Menu 1</a></li>
					<li><a href="#" data-transition="slide" data-icon="gear">Menu 2</a></li>
				</ul>
			</div>
		</div>

		<div data-role="content">
			<p>Paragraph...</p>

			<ul data-role="listview" data-inset="true">
				<li data-role="list-divider">List Divider</li>
				<li><a href="#" data-transition="slide">List Item 1</a></li>
				<li><a href="#" data-transition="slide">List Item 2</a></li>
				<li><a href="#" data-transition="slide">List Item 3</a></li>
			</ul>

			<form>
				<fieldset>
					<legend>Form Legend</legend>

					<div data-role="fieldcontain">
						<label for="input1">Input 1</label>
						<input id="input1" />
					</div>

					<div data-role="fieldcontain">
						<label for="input2">Input 2</label>
						<input id="input2" />
					</div>

					<div data-role="fieldcontain">
						<label for="toggle">Toggle</label>
						<select id="toggle" data-role="slider">
							<option value="off">Off</option>
							<option value="on">On</option>
						</select>
					</div>

					<div data-role="fieldcontain">
						<input id="checkbox" type="checkbox" />
						<label for="checkbox">Checkbox</label>
					</div>

					<div>
						<input type="submit" value="Submit" data-icon="check" data-theme="b" />
					</div>
				</fieldset>
			</form>
		</div>

		<div data-role="footer" data-position="fixed">
			<h4>
				Footer
			</h4>
		</div>
	</div>
</body>
</html>

For more information, read the jQuery Mobile demos & documentation and play around with Codiqa, a prototyping and interface-building tool for jQuery Mobile.


Webapp Issue on the iPad Mini

We got a bug report that our webapp was not working on the iPad Mini. It was working fine on Safari on the desktop. We did some debugging and noticed that our Ajax POST calls, jQuery $.post() to be more precise, were being triggered but we did not see the requests hitting to the server. A quick search on Google led us this Stackoverflow post. We tried the Apache config change so we don’t need to make any application changes but it didn’t work for us. So we tried the $.$.ajaxSetup() fix.

$.ajaxSetup({
    type: 'POST',
    headers: { "cache-control": "no-cache" }
});

This worked well for us. Thanks to Dave at Stackoverflow for the solution!


Quick Spring Mobile 1.0 Tutorial

This is a quick tutorial on Spring Mobile 1.0. You will need Eclipse with m2e to follow the steps below.

1. In Eclipse, create a new Maven Project using the spring-mvc-jpa-archetype.

New Maven Project

New Maven Project

2. Add the spring-mobile-device dependency to pom.xml.

	<dependency>
		<groupId>org.springframework.mobile</groupId>
		<artifactId>spring-mobile-device</artifactId>
		<version>1.0.0.RELEASE</version>
	</dependency>

Maven Add Dependency

Also add the java servlet API, which we will be used to import HttpServletRequest in the unit test later.

	<dependency>
		<groupId>javax.servlet</groupId>
		<artifactId>servlet-api</artifactId>
		<version>2.5</version>
		<scope>provided</scope>
	</dependency>

Spring Mobile needs Spring MVC 3.1, so change

	<spring.version>3.0.5.RELEASE</spring.version>

to

	<spring.version>3.1.1.RELEASE</spring.version>

3. Add the following Spring Mobile interceptors in servlet-context.xml.

	<interceptors>
		<!-- Resolve the device that originated the web request -->
		<beans:bean class="org.springframework.mobile.device.DeviceResolverHandlerInterceptor" />

		<!-- Manage the user's site preference -->
		<beans:bean class="org.springframework.mobile.device.site.SitePreferenceHandlerInterceptor" />

		<!-- Redirects mobile users to domain.com/quickspringmobile/spring/m/ -->
		<beans:bean class="org.springframework.mobile.device.switcher.SiteSwitcherHandlerInterceptor" factory-method="urlPath">
			<beans:constructor-arg value="/m" />
			<beans:constructor-arg value="/quickspringmobile/spring" />
		</beans:bean>
	</interceptors>

These 3 interceptors enable device resolution, site preferences, and site switching, respectively. Device resolution tells you if the user is mobile or not. Site preferences gives the user the ability to switch between mobile or desktop. Site switching gives you the ability to redirect users to a dedicated mobile site.

4. The resolved device is available under the currentDevice request attribute. The site preference is available under the currentSitePreference request attribute.

You can pass the current Device to your @Controller methods by configuring DeviceWebArgumentResolver. You can also pass the current SitePreference by configuring SitePreferenceWebArgumentResolver.

	<annotation-driven>
		<argument-resolvers>
			<beans:bean class="org.springframework.mobile.device.DeviceWebArgumentResolver" />
			<beans:bean class="org.springframework.mobile.device.site.SitePreferenceWebArgumentResolver" />
		</argument-resolvers>
	</annotation-driven>

5. While still in servlet-context.xml change spring-mvc-3.0.xsd to spring-mvc-3.1.xsd. You can change all XSDs to use version 3.1, but that is not required to run our example.

6. In HomeController, change the home method from

	public String home(Model model) {

to

	public String home(Model model, Device device, SitePreference sitePreference) {

Then change the String

	"This is the message from the controller!"

to

	"deviceIsMobile= " + device.isMobile() + " prefersMobile=" + (sitePreference == SitePreference.MOBILE)

The add the necessary import statements.

	import org.springframework.mobile.device.Device;
	import org.springframework.mobile.device.site.SitePreference;

Add the controller method for handling mobile requests. This just adds an extra log and calls the same home controller method.

	@RequestMapping(value = "/m/", method = RequestMethod.GET)
	public String mobile(Model model, Device device, SitePreference sitePreference) {
		logger.info("Welcome mobile!");
		return home(model, device, sitePreference);
	}

7. Change the following line in HomeControllerTest from

	Assert.assertEquals("home", controller.home(model));

to

	HttpServletRequest request = new MockHttpServletRequest();
	Device device = DeviceUtils.getCurrentDevice(request);
	Assert.assertEquals("home", controller.home(model, device, SitePreference.MOBILE));

This will make your unit test class compile. Then add the necessary import statements.

	import org.springframework.mobile.device.Device;
	import org.springframework.mobile.device.DeviceUtils;
	import org.springframework.mobile.device.site.SitePreference;
	import org.springframework.mock.web.MockHttpServletRequest;

8. For site preferences, add the following before the end body tag in home.jsp.

<br />Site: <a href="?site_preference=normal">Normal</a> | <a href="?site_preference=mobile">Mobile</a>

9. To enable logging, edit log4j.xml, and change

	<logger name="org.application">

to

	<logger name="com.teamextension">

10. Run mvn tomcat:run and visit http://localhost:8080/quickspringmobile to see your project in action. Project source is also available for download.

For more information, please read the Spring Mobile Reference Manual.