Building Cross-Platform Apps Using jQuery Mobile
Nick Riggs | April 20, 2011
I recently used jQuery Mobile to build an application and was stunned at how smoothly the development process went. The framework is straight forward and well documented. While it’s still in alpha, you will find that it’s very stable and responsive.
Page Structure and Components
We are going to build a to-do application. The requirements are: 1) it works great on most mobile devices, 2) we can create new to-dos and assign them a priority and 3) we can remove to-dos from the list when we’ve completed them.
In the body tag we provided the basic page anatomy for application: a header with our title in it and a section for page content. You will notice that sections of markup have a data-role attribute. This attribute instructs the framework on how to render that element and sometimes it’s content. Elements with a data-role attribute applied are often referred to as components.
If we point a browser to our page we find that these steps have gotten us well on our way to creating a cross-platform mobile application.
The jQuery Mobile framework has used the data-role attributes we supplied to apply styles, add attributes, and, in some cases, even restructure elements. If we examine the DOM once the page has been rendered by the browser, we find that the jQuery Mobile framework has been busy.
It’s worth remembering that the jQuery Mobile framework modifies the DOM significantly as it often comes into play often when writing selectors for business logic.
We need to provide a list of existing to-dos and display the list when the user enters the application. jQuery Mobile provides a lot components for us to work with: toolbars, dialogs, buttons, select menus, etc. For the purpose of our list we are going to choose the list view component. Inside of our content component we add the list view markup.
It’s a good start but we are going to have different priorities for our to-dos; plus, we need a way to remove items. The framework makes dividing items and displaying a delete icon easy.
To create dividers, we add three new list items for our priorities and specify divider as their data-role. To add delete icons to the to-do items, we specify delete as their data-icon and wrap the inner value in an anchor tag.
We have a nice mock of what our rendered list of to-dos will look like. Let’s move on to adding a new page for creating to-do items. One option for our new page is to add a physical html file for it. That method works great if you need to render the page dynamically with server-side processing but that’s not necessary for this demo. Since our page is going to be static, we can define a new logical page inside our existing index.html file.
We’ve added a new page component as a sibling element to our existing page component. We gave our existing page component an id attribute of mainPage and new the new page component the id of addPage. Let’s go ahead and create buttons to link these two logical pages using the ids we created for them.
We have used a new data-role value button on anchor elements which will instruct the framework to render them as button components in our header. We also used the data-icon attribute to specify which icon we would like displayed on the buttons. The framework handles linking the buttons to the logical pages using the href attribute. The result is navigation between our two logical pages with a sliding transition animation.
Let’s fill out our create page. We need to allow the user to specify a description and priority for the to-do. An input element will be perfect for the description and a select element will work nicely for specifying a single priority.
We didn’t specify a data-role for the input, select, and label elements as we did for the list view component. This is because the framework doesn’t need a hint on how to render these components since they are defined explicitly by the tag’s name. However we did wrap the new components in a fieldcontain component. While this component isn’t required, it provides some nice rendering benefits: 1) A single line will be rendered at the bottom of the set providing some visual separation of fields and 2) The orientation of label in respect to the control will be rendered optimally based on horizontal screen resolution of the device.
We also set the select component’s data-native-menu to false. This will cause the framework to render a theme-friendly menu of the list items instead of displaying the browser’s default drop down.
We won’t dive into a deep explanation of how our Model class is working. You can dig into it for a greater understanding or just accept that it can load(), save(), remove() and getItems().
As with most jQuery code, we wrapped our code in the $(document).ready() event closure. Future snippets will omit this detail but should be contained in the closure as well.
Let’s create an instance of our Model class to work with along with an array to hold a reference to our list headers.
The model variable points to an instance of our Model class. The listHeaders array will contain each of the list items in our list view that are dividers, in our case the three that represent priority. Let’s add a custom data-priority attribute to each of the dividers to specify which priority the divider represents. These values will correspond to the constants we setup in the Model class: IMPORTANT = 2, NORMAL = 1 and LOW = 0.
Next, we create a self-invoking function to fill the listHeaders array with dividers.
We now that we have an easy way to reference our dividers by priority. Let’s create a function that will take a to-do object, bind it to an html template and insert the result under the appropriate priority divider. From our Model class, we can see that to-do objects simply have a text string and a priority integer.
We have laid the ground work to be able to create, save, and render to-do items. Now we can tie it all together in the create button’s click event.
We get the priority from the todoUrgency select component and the text from the todoDescription input component. We create a new to-do object using the model’s create function. This function also handles saving the object in the cookie. We call renderItemElement and pass the new object which handles binding and inserting the to-do into the DOM. Since we have dynamically added an item to the list view component, we call the refresh command to re-render the component. The final two lines of code reset the todoUrgency and todoDescription components to their original states.
Now that we can add items to our list, let’s implement functionality for removing them. We’ve already used the data-icon attribute to instruct the framework to render a delete icon on each list item. We just need to catch a list item’s click and remove the item from both the model and list view.
Instead of attaching a handler to each item, we delegate the list item’s click event to the todoList. First we remove the object from the model. The remove method also handles saving the change to our cookie. Next we use a slide up animation for the visual removal of the item. Finally, once the animation has completed, we remove the element from the DOM.
As a final step, we need to render this initial view of all the items when the user first opens the application. For this we will create another self-invoking function.
We use the model’s getItems function to get a list of existing items, which we loop through and render using the renderItemElement function. Once again, we call refresh on the listview component since the items were dynamically appended.
The demand for mobile applications is growing in both the consumer and business sectors. The demand for an application to support multiple devices is growing as a result of the device market becoming more divided. jQuery Mobile introduces a unique opportunity for applications to support multiple devices without developers needing to learn multiple platforms. Best of all as web developers we are working in the platform we love – the web.
This introduction only scratched the surface of what jQuery Mobile has to offer. For example the framework handles navigation to external pages seamlessly with AJAX. It provides a rich theming system for customizing the look and feel of your pages. And as mentioned before, there is a long list of useful components for rapidly delivering user interfaces.
Working example: http://examples.nickriggs.com/todo/
For more information on jQuery Mobile and complete documentation, be sure to visit the official site: http://jquerymobile.com/
About the Author