Vernon Kesner

jQuery, JavaScript and other Front-end Development Tips and Tools

jQuery Mobile: Dialogs and Popups

In the last jQuery Mobile post, we talked all about Pages with jQuery Mobile. I want to follow that up with a post about dialogs and popups because they have a lot more similarities with jQuery Mobile pages than you would think.

Dialogs

Dialogs are a great way to present a modal window to users that requires their interaction. These are often best used when the user has an action to perform (e.g. confirming an action before moving forward).

Using jQuery Mobile, there are two different ways to create a dialog. For the most part, you can think of dialogs in a very similar manner to that of a page using jQuery Mobile. The first way we will look at creating a page to be used as a dialog, is strikingly similar to a typical page.

A jQuery Mobile dialog-only page
1
2
3
4
5
6
7
8
9
10
11
<div data-role="dialog" id="myDialog">
  <div data-role="header">
      <h1>My dialog heading</h1>
  </div>
  <div data-role="content">
      <p>Content goes here.</p>
  </div>
  <div data-role="footer">
      <h3>And my footer...</h3>
  </div>
</div>

The snippet above will look very similar to a page using jQuery Mobile. The difference here is the value of data-role. Rather than page, we set a value of dialog and then provide a corresponding id attribute to link to.

This creates a standalone dialog page that is only usable as a dialog. The benefit to creating a standalone dialog page is that any links to the dialog do not require a data-rel attribute which we’ll discuss next.

Opening a dialog from a link

While sometimes dialog-only type pages are okay, you are not required to create dialogs this way. Any standard jQuery Mobile page can be opened as a dialog by simply adding a data-rel="dialog" attribute to a link.

Linking to a jQuery Mobile page as a dialog
1
<a href="yourpage.html" data-rel="dialog">Open as a dialog</a>

When the above anchor linked is tapped or clicked, jQuery Mobile will turn the data-role="page" element into data-role="dialog" and will display the linked page styled as a dialog.

Below is a CodePen example showing the different ways that a jQuery Mobile dialog can be opened using nothing but HTML5 data-attributes.

If the embedded pen below doesn’t function correctly, check it out on CodePen.

Check out this Pen!

Opening a dialog programmatically

You aren’t required to use data attributes to create dialogs using jQuery Mobile. The dialog widget (as well as every jQuery Mobile widget) has a programmatic way to enable the functionality as well using the $.mobile.changePage method.

Programmatically create a jQuery Mobile dialog widget
1
2
3
4
5
// Open a standard page as a dialog
$.mobile.changePage( "yourpage.html", { role: "dialog" } );

// Open a page/dialog from a multi-page document
$.mobile.changePage( "#pageId", { role: "dialog" } );

Transitions

By default, jQuery Mobile dialogs are shown with a pop transition. However, just like any jQuery Mobile page, you can alter the transition used by adding a data-transition attribute to your link.

Open a dialog with a flip transition
1
<a href="yourpage.html" data-rel="dialog" data-transition="flip">Open with flip</a>

You can use any transition property including none for opening a jQuery Mobile dialog widget. Just keep in mind that as with standard page transitions, if 3D transforms are not supported a fallback to fade will be used.

Dialogs and State

It’s important to point out that dialogs are not included by jQuery Mobile in the browser history. For example:

  1. A user starts out on page1.html
  2. They perform an action that presents them a dialog
  3. In the dialog they perform an action that takes them to page2.html
  4. They press the back button from page2.html and return to page1.html, not the dialog.

Nothing like the API docs

For complete information on the methods, events and options available with jQuery Mobile’s dialog widget check out the dialog API.

Popups

Popups are very similar to dialogs but there are a lot more use cases bit more with popups. One thing that is very important to remember is that the data-role="popup" element must be within the data-role="content" section.

Here’s a CodePen examples showing some real world use cases for jQuery Mobile’s popup widget. These examples are out of the box with no custom JavaScript additions, simple HTML5 data-attribute configurations.

If the embedded pen below doesn’t function correctly, check it out on CodePen.

Check out this Pen!

Positioning a popup

You can control how and where the popup is positioned when it is opened. By default, popups will show directly over the clicked element. Quite like a simple tooltip.

However, if you prefer to position your popup differently you can do so with a simple data-position-to attribute on the link opening the popup. If you plan on dynamically updating the content of a single tooltip container, this is actually quite nice. You can use a single container and display it as a tooltip or even a lightbox based off of the link opening it.

Control the popup widget position
1
2
3
4
5
6
7
8
<!-- Position vertically/horizontally centered to the window -->
<a href="#tooltip" data-rel="tooltip" data-position-to="window">Open with window</a>

<!-- Position according to a selector! -->
<a href="#tooltip" data-rel="tooltip" data-position-to="#mySelector">Open with window</a>

<!-- Position vertically/horizontally centered to origin (default) -->
<a href="#tooltip" data-rel="tooltip" data-position-to="origin">Open with window</a>

Using a popup as a lightbox

jQuery Mobile’s CSS framework includes rules that make using the popup widget as a lightbox dead simple. Because of this, images that are immediate children of the data-role="popup" container will scale to fit the screen. The one issue you may run into is that this doesn’t always adjust the height to screen height across browsers. That can be taken care of with a small bit of JavaScript to set the max-height of the image.

You may want to also include an overlay with your lightbox, like the example use case above. Once again, jQuery Mobile makes this quite simple to do.

Add an overlay to your popup
1
2
3
<div data-role="popup" id="yourPopupID" data-overlay-theme="a">
  ...
</div>

Creating popups programmatically

By default, any page that contains a div with a data-role="popup" attribute will be automatically initialized. Just like other jQuery Mobile widgets though, the popup widget gives you a way to programmatically create it as well and it follows standard syntax and API calls you are already used to with jQuery.

Instantiate a jQuery Mobile popup widget
1
$( "#yourPopup" ).popup();

Opening and closing popups programmatically

All jQuery Mobile widgets are based off of jQuery UI’s Widget Factory pattern. This creates a lot of commonality in how new widgets are developed, making it easier for developers to use widgets and create custom widgets of their own.

jQuery UI’s Widget Factory gives you the ability to call any public methods of your widget by simply calling the widget function and passing an argument with the method name to call.

Call a widget method the Widget Factory way
1
$( "#yourSelector" ).yourWidget( "theMethod" );

For the popup widget in jQuery Mobile, this makes opening and closing popups programmatically very simple.

Open and Close a popup
1
2
3
4
5
// Open a popup
$( "#yourPopup" ).popup( "open" );

//Close a popup
$( "#yourPopup" ).popup( "close" );

Transitions

The popup widget does not use a transition by default, although you can use any of the native transitions. The nature of the general use case for the popup calls for the information to be displayed as quickly as possible, driving the default data-transition value of none.

Open a popup with a pop transition
1
<a href="#yourPopup" data-rel="popup" data-transition="pop">Open with pop</a>

For performance reasons, the jQuery Mobile team recommends using simpler animations such as pop, fade or none for the popup widget. In my testing, fade tends to be smooth and quick while still looking nice.

Making a popup modal

As of jQuery Mobile 1.3.0, popups now have a data-dismissible attribute that you can add to the data-role="popup" container. When this value is set to false, the popup will not close when you tap outside of it making it “modal” like a dialog widget.

Popups and State

Just like dialogs, popups are not included by jQuery Mobile in the browser history. If popup content links a user to a new page and they press the back button, they will go back to the original page without the popup open.

Nothing like the API docs

For complete information on the methods, events and options available with jQuery Mobile’s popup widget, check out the popup API

What’s next?

Next up in the jQuery Mobile series, we’ll dive into jQuery Mobile listviews and talk about displaying data and using them for navigation.

jQuery Mobile: Pages

In the last post we went through an introduction to jQuery Mobile that should hopefully have given you a basic understanding of jQuery Mobile and how it works. In this post, we’re going to talk all about pages from a jQuery Mobile perspective.

Let’s take a look at an example page structure:

jQuery Mobile Page
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<html>
<head>
  <title>Our jQuery Mobile Page</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="css/jquery.mobile-1.3.0.css">
  <script src="js/vendor/jquery.js"></script>
  <script src="js/vendor/jquery.mobile-1.3.0.js"></script>
</head>
<body>
<div data-role="page">
  <div data-role="header">
      <h1>Your header</h1>
  </div>
  <div data-role="content">
      <p>You are stepping into the unknown... well, not so much the unknown, but it's fun anyway!</p>
  </div>
  <div data-role="footer">
      <a href="#">Footer link</a>
  </div>
</div>
</body>
</html>

In the introduction post, we covered how jQuery Mobile uses data-attributes. If you missed that and don’t completely understand, go check it out.

The meta name="viewport" tag

Before we get into the nitty-gritty about pages, I want to first point out the meta name="viewport" tag in the sample document above. It’s very important that you include this in your document, as without it many browsers will create a “virtual page” that is sized around 900 pixels. This makes it work well with desktop based browsers but will often result in pages that seem zoomed out and really wide on other devices. This meta tag makes sure that the width will be set to the pixel width of the screen.

Header Toolbars

In our example HTML document, we have a header defined with a typical h1 setting up the main bit of the page. In this article, we’re going to look at both headers and footers more from a toolbar approach.

Adding buttons to your header
1
2
3
4
5
<div data-role="header">
  <h1>My heading</h1>
  <a href="#home" data-icon="home">Home</a>
  <a href="#menu">Menu</a>
</div>

In the snippet above we have a standard jQuery Mobile header that includes a heading and two links. The screenshot below shows a screen capture of what that looks like.

jQuery Mobile Header with Buttons

jQuery Mobile does some interesting things with content that shows up in our header.

  1. Links are automatically styled as buttons
  2. The first link is automatically used as the left button
  3. The second link is automatically placed as the right button
  4. Heading text is auto-centered

You can also add a ui-btn-left or ui-btn-right class to either link to control their placement.

Positioning

In addition to default inline positioning for toolbars, jQuery Mobile gives us two additional ways to work with fixed toolbars. The simplest way to implement a fixed toolbar is to add data-position="fixed" to your data-role="header" element. This will cause the header to remain fixed to the top of your document while your document is scrolled.

The other option with a fixed toolbar is fullscreen mode. You can enable a fullscreen fixed toolbar by adding data-fullscreen="true" to your data-role="header" data-position="fixed" element. The fullscreen fixed toolbar will cover the content and follow a show/hide pattern following a tap or click on the content area.

Below is a CodePen example of a fixed header set with full-screen enabled. Click the content area to see the toolbar show and hide.

Check out this Pen!

Style at your leisure

If you prefer to control your own styling and do not want jQuery Mobile to auto-enhance your HTML, simply wrap your content in an empty div.

Prevent header auto-enhancement
1
2
3
4
5
<div data-role="header">
  <div>
      <h1>Don't enhance me!</h1>
  </div>
</div>

Content Area

Within your content area, you can include content just as you normally would in any other HTML page. You can also include jQuery Mobile widgets and they will be auto-enhanced even when they are loaded via Ajax.

Example content area that includes a button
1
2
3
4
<div data-role="content">
  <p>Content goes here.</p>
  <a href="yournextpage.html" data-role="button">Next page</a>
</div>

Footer Toolbars

There are many similarities between header and footer toolbars. For example, the same positioning techniques that we talked about for header toolbars can also be applied to footer toolbars as well using data-position="fixed" and data-fullscreen="true".

There are a few differences between header and footer toolbars to be aware of:

  • Just as in your header, links are automatically styled as buttons. However, they are not automatically placed to the left and right. You can still apply the ui-btn-left and ui-btn-right classes if you desire.
  • You can create a persistent footer toolbar by applying a data-id attribute to your data-role="footer" element. Pages loaded via Ajax with a matching data-id will consider any updates and keep the toolbar persistent. More about this in a moment.
  • You can apply a ui-bar class to your data-role="footer" element to give you a bit of padding so that your buttons do not look squished in.

Persistent Footer

A widely used practice for the data-role="footer" element is to implement it as an app-like navbar. jQuery Mobile makes this ridiculously easy to implement and persist across your pages.

A persistent footer with a navbar
1
2
3
4
5
6
7
8
9
10
11
12
<div data-role="footer" data-position="fixed" data-id="nav">
  <div data-role="navbar">
      <ul>
          <li>
              <a href="index.html" data-icon="home" class="ui-btn-active ui-state-persist">Home</a>
          </li>
          <li>
              <a href="settings.html" data-icon="settings">Settings</a>
          </li>
      </ul>
  </div>
</div>

The snippet above shows the implementation of a fixed footer that utilizes a jQuery Mobile persistent navbar widget.

For subsequent pages, you would recreate the same data-role="footer" element on each page giving them matching data-id attribute values. To select which link is treated as active, add class="ui-btn-active ui-state-persist".

Also in the example snippet, you’ll notice that each a tag has a data-icon attribute. This sets the icon to appear on the nav bar link. On a navbar widgets, icons always appear above the text of the button. If you want the icon to appear in a different position, just add a data-iconpos attribute to your data-role="navbar" element with a value of top, right, bottom or left.

Ajax Navigation pattern

jQuery Mobile has a navigation system that will automatically hijack standard link and form submissions and route them as an Ajax request. Based on browser support, jQuery Mobile will then use either hashchange or popstate (falling back to an iframe to support hashchange) to dynamically update the URL and finish with a CSS3 transition.

There are also multiple ways that you can opt-out of jQuery Mobile’s Ajax navigation:

  1. Adding data-ajax="false" to an anchor will cause the link to load normally.
    • You can also add data-ajax="false" to a parent element which will short-circuit Ajax handling for all child elements, but only if ignoreContentEnabled is set to true inside of your mobileinit handler.
  2. Adding rel="external" defines the link as an external link which will disable the Ajax pattern.
    • I’m sure this may be obvious, but this should only be used on actual external links.
  3. Any external link will load normally.

Page transitions

jQuery Mobile provides several different transitions that you can apply to any standard link or form submission that utilizes jQuery Mobile’s Ajax navigation. By default a fade transition will be used, but there are currently 9 different transitions you can apply.

Setting the transition on an anchor tag
1
<a href="page2.html" data-transition="slideup">I'll use slideup</a>

The above snippet shows how easy it is to apply a specific transition to a link. This can also be set globally in your mobileinit handler which will talk about when we get to the API part of the series.

All transitions are CSS-based transitions, and only browsers that support 3D transforms are supported. Platforms such as Android 2.x and browsers that do not support 3D transforms will fallback to the standard fade option.

Below is a CodePen example showing several of the page transitions available in jQuery Mobile. Use the back button in the example to see how jQuery Mobile automatically applies the animation in the reverse for the “out” animation. The way the embedded CodePen example loads, you will need to go 2 transitions in to see the reverse effect using the back button.

Reminder: If your browser does not support 3D transforms, each transition will simply fallback to the fade transition.

Check out this Pen!

Multi-page Documents

We’ve just talked about prefetching, but another useful feature that jQuery Mobile provides is the ability to build multiple pages within a single HTML document. There are times where you may prefer this approach to prefetching. Setting up multi-page documents is a breeze, as you simply include multiple <div data-role="page"> blocks in your HTML.

Multi-page document example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div data-role="page" id="page1">
  <div data-role="header">
      <h1>Page 1 heading</h1>
  </div>
  <div data-role="content">
      <p>Page 1 content with a <a href="#page2">link to page 2</a></p>
  </div>
</div>
<div data-role="page" id="page2">
  <div data-role="header">
      <h1>Page 2 heading</h1>
  </div>
  <div data-role="content">
      <p>Page 2 content with a <a href="#page1">link to page 1</a></p>
  </div>
</div>

The example snippet above creates two jQuery Mobile pages. If you were to place that inside of an HTML document, clicking the links within the content wells would update the document hash and create a page transition just like you were pulling in a new page via Ajax.

Word of Caution

Consider your multi-page documents carefully and do not let the size of your DOM get bloated. This can result in performance degradation and memory issues on some devices.

IE7 support

If you are one of the unlucky folks where IE7 support is required there can be some issues with back button behavior. If IE7 support is important, standalone pages will most likely be a better approach.

Caching Pages

Looking at multi-page documents leads to the conversation around caching pages with jQuery Mobile. jQuery Mobile works to keep the DOM as small as possible. One way you see this is in the way jQuery Mobile cache’s pages loaded via Ajax.

When a page is loaded via Ajax it is flagged for removal when navigated away from. When a separate page is loaded in via Ajax, the previously viewed page is removed from the DOM and replaced with the new active page. This does not affect existing markup for the current page itself, only DOM nodes appended after an Ajax request.

Removing the page keeps the DOM small and the browser should be able to retrieve the HTML file of the removed page from its cache. If not, a new request will be made to fetch the data.

You can tell jQuery Mobile of certain pages that you want to be cached and not removed with a simple data-attribute.

Tell jQuery Mobile to Cache a Page
1
2
3
<div data-role="page" data-dom-cache="true">
  ...
</div>

Word of Caution

You should pay special consideration when thinking of your caching strategy. Be mindful of the size of your DOM. The larger your DOM grows the more opportunity for performance degradation and memory issues across some devices. For caching, it is often a much better appraoch to leverage browsers’ default caching mechanism by using proper Expires and Cache-Control HTTP headers.

Prefetching Pages

jQuery Mobile gives you the ability to prefetch pages, loading them into the DOM for quick access when a user navigates to a specific page.

Set certain links to prefetch content
1
2
3
4
<div data-role="content">
  <a href="yourfuturepage.html" data-prefetch="true">I use prefetching!</a>
  <a href="idontgetit.html">I don't use prefetching.</a>
</div>

The short snippet above includes two links. When the pageinit event is triggered, jQuery Mobile will automatically fetch the content for yourfuturepage.html because that links utilizes the data-prefetch data attribute.

You can also prefetch pages programatically with JavaScript:

Programatically Prefetch a Page
1
$.mobile.loadPage( 'yourpage.html', { showLoadMsg: false } );

Word of Caution

Just as in the caching section above, there is a word of warning that goes along with prefetching pages. Be mindful of the size of your DOM. The larger your DOM grows the more opportunity for performance degradation and memory issues across some devices.

What’s next?

In the next post we’re going to take a look at Dialogs and Popups to see how closely they tie together with what jQuery Mobile considers a page. After that we’ll jump in to some navigation patterns and look at listviews.

An Introduction to jQuery Mobile

With the recent release of jQuery Mobile 1.3, there’s no time like now to start a jQuery Mobile series. This initial post will introduce jQuery Mobile and lay the foundation for the series ahead.

Why jQuery Mobile?

One of the greatest strengths of jQuery core is the entry point for newer developers. Granted, jQuery does make it easy to do bad stuff, but it also makes it much easier for new folks to get into JavaScript.

jQuery Mobile is creating the same entry point in a whole new way with jQuery Mobile. With mobile development, there are still many open questions and problems that the community is working through. jQuery Mobile, provides a great coverage for many of the mobile device quirks as well as providing support to desktop browsers.

Put simply, jQuery Mobile makes it easy to get started building a site or even standalone app (ahem… PhoneGap) without requiring you to know things like how tap events fire on radio buttons in Android 2.3 on XYZ Phone vs. iOS 6.

It’s not just about ease-of-introduction, the API is beautiful just like jQuery core allowing you the freedom to customize to your needs.

HTML5 Data Attributes

HTML5 data attributes are leveraged heavily when implementing jQuery Mobile pages and widgets. These data attributes not only allow you to initialize but also configure widgets and pages. Application-wide configuration should be handled within a mobileinit handler, but we’ll cover that in a different post.

Let’s take a look at some actual code to see how these data attributes are used.

A rough page structure
1
2
3
4
5
6
7
8
9
10
11
<div data-role="page" id="services">
  <div data-role="header">
      <h1>My services rock</h1>
  </div>
  <div data-role="content">
      <p>There's nothing like good services to get you going.</p>
  </div>
  <div data-role="footer" data-position="fixed">
      <h4>Wow, I don't have many services.</h4>
  </div>
</div>

The code snippet above gives you a breakdown of a simple jQuery Mobile “page”. We’ll go through the idea of “pages” and what they mean from a jQuery Mobile perspective in the next post. For now, let’s just check the data attributes out.

  • div with data-role="page": For your containing elements, you’ll most likely always start with a data-role attribute. This declaration lets jQuery Mobile know that this should be treated as a new “page”.
  • div with data-role="header": Again we have another data-role attribute, calling this piece out as our header container.
  • div with data-role="content": We’ve used HTML5 elements up to now but took a step back here using a simple div. Why not use main here? Remember that question. We’ll answer it in the next section.
  • div with data-role="footer" and data-position="fixed": This is the oddball out of the bunch. Each element we looked at had a data-role attribute, but the footer has this extra data-position attribute. What gives? This is the ease of configuration mentioned at the beginning. This is telling jQuery Mobile to treat the footer as a position: fixed style footer.

*Note: jQuery Mobile will fall back to a standard footer where position: fixed is not well supported.

jQuery Mobile’s API docs has an awesome data attribute reference sheet for the various data attributes supported and implemented by jQuery Mobile.

The Ajax Navigation Pattern

When getting started with jQuery Mobile, it’s important to get an understanding of how the navigation system is implemented. Ajax is relied on heavily intercepting both standard anchor links as well as form submissions to handle routing “pages” in jQuery Mobile.

When a link is clicked (or form submitted) the system hijacks the request and performs an Ajax request. The returned response is parsed for the data-role="page" attribute and subsequently injects that code into the DOM and finally the selected (or default) page transition completes.

There are several things to be aware of:

  • No reinstantiation necessary! Widgets defined with data attributes will automatically be enhanced before the transition happens to show the new content.
  • No page specific JS or CSS. As the only thing coming in is what is received in response that fits the data-role="page" attribute, any associated JS or CSS is dropped and not included.
  • CSS classes FTW! One potential “gotcha” with jQuery Mobile’s Ajax navigation system is ID clashes as new pages are brought in and injected into the DOM. This is especially important for forms that may get consumed. Think twice about any IDs you use on your DOM elements (or you know… just use classes), and consider the naming conventions for your form fields.
  • Friendly page titles. One nice feature is the updating of the page title. When a new page is loaded, the page title is updated to match that of the new page title coming in. You can also override the page title, but we’ll talk more about that when we break down pages.

With the release of jQuery Mobile 1.3.0, there was the addition of a new event (navigate) and method ($.mobile.navigate) that straightens out some URL alteration events and gives more information in navigate bindings (docs).

*Note: You can configure the system to preven the automatic hijacking of links and form submissions. This is good to know if, for example, you want to build a Backbone.js application with jQuery Mobile and you prefer to use Backbone’s router.

What’s next?

So we’ve gotten to dig into jQuery Mobile a little bit in this first post but next we’ll start dissecting pages. We’ll look at exactly what pages are and how they are defined and look at some of the configuration options we can set in straight from the HTML. After that we’ll start digging in to some of the widgets and see some changes in the latest version of jQuery Mobile. To wrap it up, we’ll take a bit of a dive into the API itself to see how we can customize jQuery Mobile and build some awesome mobile first sites.

Using Frontmatter in Partials Within Middleman

I was recently working with Middleman on a toolset for generating dynamic components. What I quickly discovered was that you couldn’t use Frontmatter inside of partials.

In a lot of use cases this may not be a big deal. What I was trying to do though, I needed that ability.

The goal is to serve snippets of components (e.g. a “cta” snippet). This partial file would include frontmatter that represented sample data. When included in a page or layout, I wanted to allow the partial to use its sample data from the partial. By passing a hash, though, I wanted override that data.

Here is the necessary code for the helper as well as an example partial with frontmatter as well as how it would be included in a layout or page.

This helper expects HAML to be used and a specific structuring and naming of partials (e.g. /source/partials/components/_COMPONENTNAME.html.haml) although it could be updated pretty easily. The helper would go in your config.rb file in the root of your Middleman app.

The New VernonKesner.com

Hey folks! Thanks for dropping by. As you can see, this is pretty much brand spankin’ new. Back in February 2002, I started freelancing and it’s been a pretty exciting journey to get to where I’m at now. I won’t bore you with those details (unless you really do want to know more about me).

This is an Octopress powered blog and this is the default theme. When I started looking at Octopress, I realized I could spend a bunch of time trying to pull together a slick design or I could get this up and start writing and design along the way. If the Octopress default theme wasn’t so slick, I may have waited.

Hopefully, I can use this to interact with the community and share some of the knowledge that I’ve gained over the past decade plus.