Dynamically creating jQuery Mobile radio buttons with Mustache
Filed under: jQuery Mobile
comments (6) Views: 5,896
This afternoon I had a reader email me with a question about dynamically creating radio buttons in a jQuery Mobile app after load and getting them to render. He was using my previous blog post on refreshing jQuery Mobile components but couldn't get the radio buttons to work. So I whipped up a quick demo to make sure it was possible. Turns out it is, but there's a trick.
The first thing I did was to write it up procedurally using jQuery object creation. It works, but its long and ugly; plus there was duplication. Here's what I came up with first:
Yep, it's ugly all right...pretty verbose too. But it's all there. Check the demo and you'll see that "the hard way" runs just fine and allows you to pick your favorite seasoning. But I knew there was a better way to accomplish this task. So I reached for the Mustache templating language. You might recall that we've looked at Mustache before. Performing this same task with Mustache was much simpler, easier to read, and didn't duplicate code, which is a great thing. Let's look at the code after refactoring to use Mustache:
In this case I'm defining the template as a string of HTML right inline. You probably wouldn't do this in production but taking this route helps me avoid an AJAX call. I'm also hard-coding the data being passed into the template renderer, which in a real app you'd more than likely be looping over a data set. Run the demo though and you'll see that the easy way results in tasty snacks for everyone.
Here's the part that was likely throwing off our reader. You'd think that after defining the radiogroup object through hard-coding or templating, you could immediately render it using .trigger('create') or .checkboxradio('refresh') but you'd be wrong. Using the former merely runs without actually converting the plain HTML to jQuery Mobile elements, and the latter actually throws an error.
Uncaught cannot call methods on checkboxradio prior to initialization; attempted to call method 'refresh'
It appears that when dynamically creating elements and inserting them in this manner you have to first insert them into their resting place, then render their container using .trigger('create') as in the second example above.
Hope this helps someone else.
If this article was interesting, or helpful, or even wrong, please consider leaving a comment, or buying something from my wishlist. It's appreciated!
Thanks a lot for this, Andy!
The "trick" for me was that I had to use .trigger('create') instead of .checkboxradio() or .controlgroup() -- is this actually in the official JQM docs at all?! -- and the 2nd part of the trick is triggering the event on the fieldset's parent and not on the fieldset itself.
Working swell for me now. Thanks again!
I do like Mustache. Swig is another cool JS template tool.
Zachary Johnson - May 18, 2012 01:54 pm
Glad to help Zach...
andy matthews - May 19, 2012 09:13 pm
i recently did a mobile site using jquery mobile and liquid. at first i started using mustache, but I found it a little bit limiting for project. In its defense though, that's the whole point of mustache , to just apply a template to data and not filter or massage it in any way. Liquid allows you to use filters to format the data while it's being applied, which is nice when you need to format dates or truncate long lines of text. if you get a chance, give it a whirl. https://github.com/tchype/liquid.js
tony petruzzi - May 22, 2012 11:17 am
I think there is one pitfall most people will encounter that you managed to avoid with your non-production code.
Say I have a template somewhere on the page within a hidden div with an ID of "template"
I want to render this template to another div called "Content" like:
$(Mustache.to_html(someData, $("#template").html()).appendTo($("#content")).trigget("create")
The problem with the code above is that the page will have likely already called create on the elements within "#template" and you will essentially be calling create a second time on elements that were already created during page load.
The trick here is to make sure that these elements were not rendered the first time (if you have them like a string in your example this is safe). I am still trying to find a way to pull this off while still using html inline and not resorting to a string.
I wrote to you earlier about my issues with the checkboxes in your github font icon project, I belive this issue with the inline html is why my checkboxes look funny
pete w - June 03, 2012 10:37 am
I'm in the same boat as pete w on this; any chance any of you successfully crossed this bridge?
Jordyn - August 22, 2012 11:10 am
Thank you, beard guy!
non-beard guy - April 10, 2013 09:41 am