Ajax, hashes & history

jQuery Mobile's navigation model

A "page" in jQuery Mobile consists of an element (usually a div) with a data-role attribute set to "page", within which ther generally tends to be div elements with roles of "header", "content", and "footer", each containing common markup, forms, and custom jQuery Mobile widgets.

The basic workflow with page loading is as follows: first, a page is requested with a normal HTTP request, and subsequent "pages" are then requested and injected into that page's DOM. Because of this, the DOM may have a number of "pages" in it at a time, each of which can be re-visited by linking to its ID attribute.

When a url is requested, there may be one or more "pages" in the response, but only the first one will be shown. The advantage of storing more than one "page" is that it allows you to pre-fetch static pages that are likely to be visited.

Hash-driven page navigation

All navigation within jQuery Mobile is based on changes in location.hash. Whenever possible, hash changes will trigger a smooth transition between the current "page" and the next, whether it is either already present in the DOM, or is automatically loaded via Ajax.

Hash values created by jQuery Mobile are always normalized as full paths relative to the URL of the first "real" page that was loaded. The hash is always maintained as a valid URL, so any "page" in jQuery mobile can be bookmarked or referenced in a link.

In general, hash changes are created whenever a link is clicked in jQuery mobile. Once clicked, jQuery mobile will make sure the link is referencing a local URL, and if so, it'll prevent the link's default click behavior from occurring, and set the location.hash to the value of the link's href attribute. However, before it can set the hash value, jQuery mobile must apply logic to convert a relative path into a full absolute path from the page that was initially loaded, because all Ajax requests are made relative to that initial page.

Hash changes are handled through the hashchange event, which is bound to the window object using Ben Alman's hashchange special event plugin (included in jQuery Mobile core).

When a hash change occurs (and also when the first page loads), the hashchange event handler will run and check if the hash references an ID of an element already in the DOM, and if not, it will make an ajax request for the url referenced in the hash. When the Ajax request is complete, the response is filtered to a subset of its content (a child element with a data-role attribute equal to "page"), and that element is then given an ID attribute equal to its hash path and inserted into the DOM.

Before showing the new page, the <base> HTML tag is updated to match the newly loaded page's path, so that any assets (css,images,js,etc) referenced on that page will be requested from a proper path.

Once the referenced page is present in the DOM, the changePage function is used to transition between the current active page and the page referenced in the hash. Page transitions happen through adding and removing classes that apply CSS animations. For example, in a slide-left transition, the exiting page is given the classes "slideleft" and "out", and the entering page is given the classes "slideleft" and "in", as well as a class of "ui-page-active" to mark it as the new "active" page being viewed. When the animation is complete, the "in" and "out" classes are removed, and the exited page loses its "ui-page-active" class.

Developer explanation of base url management:

jQuery Mobile manages http requests using a combination of generated absolute URL paths and manipulating a generated <base> element's href attribute. The combination of these two approaches allows us to create URLs that contain full path information for loading pages, and a base element to properly direct asset requests made by those loaded pages (such as images and stylesheets).

jQuery Mobile core contains 3 internal functions for manipulating a base url to be used in normalizing relative http requests:

These are called at certain times during page requests and transitions: On DOM ready, during the initial page load, a <base> element is created and appended to the <head> of the page. Immediately after that, resetBaseURL() is called to set the <base> element's href to location.pathname.

Whenever a link with a relative URL is clicked, the location.hash is set to that link's href value, prefixed with the value of getBaseURL(), which creates a full path to that file, relative to the document.

Changing the hash value triggers our hashchange event handler, which first calls resetBaseURL(), allowing jQuery Mobile to make an Ajax request to the full value of the hash (which is already a full path, requiring no base url). After that request is sent, setBaseURL() is called, which resets the <base> element's href attribute to the value of getBaseURL() and allows any references to images, stylesheets, and scripts within that page to be requested with a proper base path.

Auto-generated pages and sub-hash urls

Some plugins may choose to dynamically break a page's content into separate navigable pages, which can then be reached via deep links. One example of this would be the Listview plugin, which will break a nested UL (or OL) into separate pages, which are each given an ID so they can be linked to like any normal "page" in jQuery Mobile. However, in order to link to these pages, the page that generates them must first be requested from the server. To make this work, pages that are auto-generated by plugins use the following special ID structure: <div id="page.html&subpageidentifier">

So, for example, a page generated by the listview plugin may have an ID like this: id="artists.html&ui-page=listview-1"

When a page is requested, jQuery Mobile knows to split the URL at "&ui-page" and make an HTTP request to the portion of the URL before that key. In the case of the listview example mentioned above, the URL would look like this: http://example.com/artists.html&ui-page=listview-1 ...and jQuery Mobile would request artists.html, which would then generate its sub-pages, creating the div with id="artists.html&ui-page=listview-1", which it will then display as the active page.

Note that the ID of the element contains the full URL path, not just the portion after &ui-page=. This allows jQuery Mobile to use a single consistent mechanism that matches URLs to page IDs.

Cases when Ajax navigation will not be used

Under certain conditions, normal http requests will be used instead of Ajax requests. One case where this is true is when linking to pages on external websites. You can also specify that a normal http request be made through the following link attributes:

Form submissions

When using the ajaxform plugin, form submissions can be automated through Ajax requests, and the results can either be appended into the existing page, or injected into a new page, causing a transition. In the case of the former, the "content" div of the current page will be replaced by the "content" div in the server's response HTML.

Known limitations

The non-standard environment created by jQuery Mobile's page navigation model introduces some conditions for which you should be aware when building pages: