Worked a small mobile centric pet project recently that involved jQuery Mobile. Usually I would have use Sencha Touch, but I wanted to test out a different framework. Having used Sencha Touch / ExtJS I was used to being very programmatic, building all the boiler plate html took some getting used to. The main problem I ran into was my navigation menu, it had to be hard coded on every page. After investigating alternatives approaches and not finding any thing that suited my needs. Even the jQuery Mobile Demo Site uses a static menu on every page, not encouraging!

I started building a dynamic menu just like I would have on any jQuery site, using $(document).ready(). It wasn’t long before I ran into problems. I won’t go into detail about all the issues caused by JQM’s progresive enhancement, but it certainly caused a few hours of head scratching. Below is solution I came up with.

The HTML

This is all standard HTML taken directly from jQuer Mobile examples.

<body>
<div data-role="page" id="page1">
  <div data-theme="a" data-role="header">
    <!-- The #menu is the ID of the navigation panel element -->
    <a href="#menu" data-role="button" data-theme="c" data-rel="back" data-inline="true" data-icon="bars">
      Menu
    </a>
    <h3>
      Simple Dynamic Menu :: Page A
    </h3>
  </div>
  <!-- This is the navigation panel that opens to show the menu -->
  <div data-role="panel" id="menu" data-display="push">
    <div class="ui-panel-inner">
      <!-- This UL is the menu, where the items will be added -->
      <!-- Make sure you don't add any <li> or any other content inside it! -->
      <ul data-role="listview" class="mainMenu"></ul>
    </div>
  </div>
  <!-- /panel -->
  <div data-role="content">
    <h3>Page A (Cats)</h3>
    This simple implementation shows the simplest possible implementation of a dynamic menu.
    <p>
      <img src="img/cat.jpg">
    </p>
  </div>
</div>
</body>

Important things to note:

  1. The placement of this HTML is important. It must be inside the “page” div, but not inside the “content” div (i.e. it is a sibbling of “content”, not a child).
  2. To make the menu appear we add a button to the header. The href for the link is just a hash with the ID of the hidden panel that holds the menu.
  3. This mainMenu <ul> must be completely empty.

The Javascript

For this “simple” demo, the Javascript is very straight forward.

// The Menu items and links
var menu = [
  {
    title: "Page A (Cats)",
    url  : "simple-page-a.html"
  },
  {
    title: "Page B (Dogs)",
    url  : "simple-page-b.html"
  },
  {
    title: "Page C (Elephants)",
    url  : "simple-page-c.html"
  }
];

// For this "simple demo" we can change event to "pageinit", but for the more advanced features, it has to be bound to "pageshow"
$(document).on("pageshow", function (event) {

  var items = '', // menu items list
    ul = $(".mainMenu:empty");  // get "every" mainMenu that has not yet been processed

  for (var i = 0; i < menu.length; i++) {
    items += '<li><a href="' + menu[i].url + '">' + menu[i].title + '</a></li>';
  }

  ul.append(items);
  ul.listview('refresh'); // use cache, as ".mainMenu:empty" will no longer work (append called!)

});

Important things to note:

  1. The most important thing to note is theĀ $(".mainMenu:empty") selector. This is the most efficient one possible, as it works only on unprocessed menus.
  2. JQM preloads pages using Ajax (in order to have nice transitions), this is why a page will usually have two menus, thus have to use a CSS class not a CSS id.

 

Follow the link below to see a live demo

View Live Demo

Checkout out the full source code on GitHub.

Fork on GitHub

The GitHub project also includes a more advanced demo that shows how you could use Ajax and JSON to load the menu from a remote source.


2 Comments » for jQuery Mobile – Dynamic Navigation Menu
  1. Mark says:

    Hi Robert. Thanks for your post. I’m browsing around looking at how to link to ‘pages’ within a single HTML page. I’ve a (static – for now) list view inside my panel. The hrefs point to ‘internal’ pages. Eg. href=”#cat”, href=”#dog” etc, but this doesn’t work. Any idea why? Cheers, Mark.

Leave a Reply

Your email address will not be published. Required fields are marked *

*