Using AngularJS and jQuery Mobile
UPDATE: Well, I was hasty. What I say here is true, but offering it as a solution is incomplete. I have run into some problems by loading Angular then jQuery Mobile. Specifically, if AngularJS is loaded first, it does not ever get change events on radio buttons. If jQM is loaded first, the form works properly. Apparently, there is a bit more work that needs to go into finding a solution. It is a bummer that angular-jqm is no longer under development.
UPDATE 2: I should really write a new post explaining this. The solution I have found is to load jQuery, AngularJS, and jQuery Mobile, in that order! This way, Angular runs before jQM, but it doesn’t get locked out of the events (as explained in the previous UPDATE).
—–Original—– Skip to the solution, if that’s all you’re interested in.
I experimented with several different libraries such as doT.js, Transparency, and dust. All of them have their pros and cons, but out of those three, doT fit the bill the most. I hadn’t previously considered AngularJS, since I didn’t think we needed two full blown frameworks, but slowly the idea of using it crept up on me. We use it on another related project, and it’s always great to be able to share talent.
AngularJS has several very nice features, like data binding, services/factories/providers, and directives. Mainly, we wanted its data binding and built-in control directives (like
ng-repeat). It offers a lot of features that we don’t need, however. The great thing about AngularJS is its modularity. For example, we are letting jQM handle routing (since that’s one of its strengths), so we won’t use Angular’s routing provider. No problem! Just don’t include angular-route(.min).js.
Wondering how to get jQM and AngularJS to work well together, I found an article by Simon at simonguest.com calledjQuery Mobile and AngularJS Working Together. He proposed that jQM should be loaded first, and then Angular. If he didn’t, he “found that loading AngularJS first led to some interesting (and annoying!) UI functionality.” I have found the opposite. In fact, I am writing this post to clarify a comment I left on his blog. Hopefully, he’ll read this and offer more insight into the nature of the “interesting… UI functionality” that he just briefly mentioned.
The correct (at least in my case) load order is to load AngularJS, then jQuery Mobile. The simple reason is that AngularJS will ignore jQuery Mobiles data- attributes, but jQM doesn’t know what to do with unexpanded Angular directives. Let’s take, for example, the situation I discussed in the comment on Simon’s blog.
<ul data-role="listview" data-inset="true"> <li data-role="list-divider"></li> <li ng-repeat-start="prod in products"></li> <li ng-show="$index == 0" data-role="list-divider" ng-repeat-end></li> </ul>
Let us define our two cases as: A) jQM first, then Angular and B) Angular first, then jQM.
In case A, jQM will see an unexpanded
ng-repeat-start/end. It will apply styles to the list elements, such as
ui-last-child. The first
list-divider in the ul is fine to be labeled with class
ui-first-child. However, the second
list-divider (with the conditional statement), should not be labeled as
ui-last-child, because there will possibly be more products later. If there are more products, then this
list-divider will never be the last child. Here is a slice of the left-most side of a three product list:
For case B, AngularJS will run first and expand the
ng-repeat directive. That modified DOM is what jQM sees. Now jQM can appropriately style the elements. Here is the same slice, but with Angular loaded first:
In summary, here is what I am doing (with no adverse effects, so far):
- At the bottom of
body, load AngularJS and then jQM
- Use jQM for routing (which is the default, as long as you don’t include ngRoute)
Thanks for reading. Comment below if you have anything to add!