I’ve spent the last month coding a mobile application for a client using a very fun set of tools:
- Apache Cordova Framework (AKA PhoneGap) – A multi-platform HTML5-based mobile app framework
For my UI-rendering implementation, I chose to use the really awesome template: data-binding functionality within knockout.js to inject div “views” into a single HTML page as the user navigates around. These views are bound to knockout ViewModels and leverage the standard knockout data-bind paradigm for data rendering.
The Base Example
My knockout view models were as follows:
ApplicationViewModel – The housing VM for the entire application. It controlled the view navigation. In this example, it’s stripped down to just loading the logonViewModel for simplicity.
LoginViewModel – The VM controlling the user login/out state. In this example, it’s stripped down to a fake login call.
Page Initialization – The code to initialize the page to the correct ViewModel bindings in Knockout
The HTML Markup – The page body that is bound to my ViewModels
The UI – Functional but completely un-styled
After getting the business logic completely implemented, it was time to go back and style the app to look really killer. To do this, I chose the simplicity of jQuery Mobile’s theme-roller and it’s data attribute capabilities for theme application. This makes the maintenance of the application CSS really simple and the HTML attribute mark-up clean and concise.
This is where I ran into my first “gotcha”…
After applying my themes, I was seeing that all non-templated content was themed appropriately, but any injected div “views” weren’t getting themes applied!
Here’s the modified version of the HTML Markup from above
The resulting UI – still not styled!
So, what’s the problem here?
I and my colleagues were nearly positive that the issue lay in the timing of the dynamic content injection as it related to the theme application. After doing some research on how to re-apply jQuery Mobile themes as dynamic content is injected into a page, it turns out the solution has a few parts.
The first part to this problem is ensuring that the template view has themes applied after view-injection has completed. This is done by adding some jQuery code to the “afterViewRendered” event handler of the knockout.js template binding.
Here’s the added code as it relates to the example from above:
The resulting UI – It’s fixed!
Alas, this doesn’t work for ALL knockout-bound dynamic content.
The second part of the solution is to tell jQuery theme objects to refresh themselves whenever dynamic content from knockout.js has changed. For example, a jQuery listview (<ul data-role=”listview” />) bound to an observableArray form knockout.js will need to have it’s list view theming refreshed whenever the list changes.
The code to update a listview:
The toolset of knockout.js / jQuery Mobile / PhoneGap is a very compelling solution for rapidly developing multi-platform mobile applications. Having said that, we all need to realize there are always going to be nuances that need to be ferreted out when integrating between frameworks. This example above just happens to be one of them. If you haven’t tried using this toolset yet, I highly recommend taking the time to give it a shot.
VP of Engineering