John sent me an interesting question. He wants to make use of jQuery Mobile but needed a way to get sets of content on a page that would load only when requested. He tried using a list view but this failed to render properly for his needs. Turns out - there are all kinds of nice gems within jQuery Mobile, one of them being collapsible content items.
They are - like most things in jQuery Mobile - incredibly simple to use. Just wrap your content in a specially marked div and you get a collapsible item:
<div data-role="collapsible">
<h1>Item One</h1>
<p>
This is my content.
</p>
</div>
And that's it. Really. If you want to make the content default to collapsed, you have to write a bunch of JavaScript code... nah, I'm kidding, you just add an argument:
<div data-role="collapsible" data-collapsed="true">
<h1>Item One</h1>
<p>
This is my content.
</p>
</div>
Ok, so that's incredibly trivial. What isn't so trivial is how to make the actual content something you load via Ajax. The docs don't discuss this, but a Google search turned up this forum posting that says an event is fired when your div is collapsed or expanded. The example they provide is this:
$('div').live('expand', function(){
console.log('expand');
}).live('collapse', function(){
console.log('collapse');
});
Easy enough, right? So I whipped up a super simple static front page:
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a4/jquery.mobile-1.0a4.min.css" />
<script src="http://code.jquery.com/jquery-1.5.2.min.js"></script>
<script src="http://code.jquery.com/mobile/1.0a4/jquery.mobile-1.0a4.min.js"></script>
<script>
$('div.info').live('expand', function(){
//get the ID for this record
var record = $(this).data("record");
console.log('expanded '+record);
$(".detail", this).load("test2.cfm?record="+record);
});
</script>
</head>
<body>
<div data-role="page">
<div data-role="header">
<h1>Page Title</h1>
</div>
<div data-role="content">
<div data-role="collapsible" data-collapsed="true" class="info" data-record="1">
<h1>Item One</h1>
<div class="detail"></div>
</div>
<div data-role="collapsible" data-collapsed="true" class="info" data-record="2">
<h1>Item Two</h1>
<div class="detail"></div>
</div>
</div>
<div data-role="footer">
<h4>Page Footer</h4>
</div>
</div>
</body>
</html>
I've got two collapsible items here - hard coded. Normally this would probably be database driven. Note that I've applied a class to them as well as a data item called record. If you go up to the JavaScript, you can see I've modified the selector to be more specific. It only picks up divs with the info class. I also only care about expansion so I didn't bother with a collapse handler. Once one of my divs is opened, I grab the record value (imagine this is a database table primary key) and call a load event. test2.cfm isn't doing anything interesting but here it is anyway:
<cfparam name="url.record" default="">
<cfoutput>
This is dynamic data for record #url.record#
</cfoutput>
Archived Comments
Thanks Ray, I got it working on my jquery mobile test site:
http://m2.jhweather.com/ind...
I still have a lot of CSS to fix up... speaking of which, do you know why the content of each list element doesn't span the total width of the list? It only spans about 3/4 of the list width.
Thought you linked to the wrong demo for a second there Ray ;<). In IE-8 selecting either choice gives you a custom 403 message. Works as intended in Firefox.
Just fixed a couple jqplot errors and got my example working in IE 8:
http://m2.jhweather.com/ind...
Click on "View 24 Hour History"
I wonder if it's possible to get jQuery to NOT do a re-load after you've already expanded.
@Rick: It's the console message. If you remove it, it should work fine in IE for you. Yes - I made _that_ mistake again. ;)
@Rick: Removed the console.log just for you.
@JP: Ah, good catch there. It should NOT reopen. Give me 10 minutes.
Ok, check out
http://www.coldfusionjedi.c...
All I did was add a simple flag per record:
var done = {};
$('div.info').live('expand', function(){
//get the ID for this record
var record = $(this).data("record");
if (!done[record]) {
$(".detail", this).load("test2.cfm?record=" + record);
done[record] = 1;
}
});
Nice... I added it to my page:
http://m2.jhweather.com/ind...
Now I just need to make it all look cool. Time to dive into navigation lists.
Good article, have you seen this? "Why you should never use jquery live" http://jupiterjs.com/news/w...
I had not - and thank you. This is something I had kind of heard before - but getting out of the habit has been hard to do. (Of course, the original code was taken from the jQuery forums - so may I blame them instead? ;)
Yes you can! Maybe this is why Stackoverflow allows their uber users to edit other users content.
I tried using delegate (), but I can't seem to get it to work.
Maybe share a pastebin link with your code?
http://pastebin.com/Mzb73bjr (doesn't include the test2.cfm file it's trying to load)
But first, I need to get the delegate function to bind to the expand action.
I can get it working with:
$('*').delegate ('.info', 'expand', function (event) {...}
not sure why it won't work with:
$('.weather-station').delegate ('.info', 'expand', function (event) {...}
I had thought that delegate finds the specified nodes inside the initial selector.
Thanks - great article, clearly written and an excellent discussion with enhancements to follow :-)
Thanks Ray, why did they not mention the expand in the jquery mobile docs I wonder. Second time now I been on your site during the jquery mobile project I'm making, keep up the good work.
Glad to help. To be fair to the docs, this feels like something that isn't necessarily appropriate there - more like a jQuery Mobile cookbook type thing.
this is nice - is there a way to make the two items into a seamless grouping?
thanks
tony
Sorry, I don't understand your question.
Awsome work , have been googling this for ages works a treat
Works lovely as a test at my site http://www.homeducate.me/cg...
However, I'm trying to get it to work with:
jquery.mobile-1.4.1.min.css
jquery-1.10.2.min.js
jquery.mobile-1.4.1.min.js
and it fails (see http://www.homeducate.me/cg... ). Need those versions for other reasons :(
Any ideas?
Also, any ideas on how to display a "busy" twirly animation while the AJAX is doing its thing?
Any ideas?
You should learn to use your browser dev tools. :) As soon as I opened it I saw an error in the console: undefined is not a function
It is failing on the .live call, which was deprecated if i remember right, and should be replaced with .on.
Ah, thank you for the training :)
I tried the switch to .on but it still fails. I will tinker about with it and see what I can find. Thanks for the great code anyway and response to steer me in the right direction. It's much appreciated!
hi,
i am also facing the same issue.works good with old jquery but not with latest 1.4.2 jquery mobile and 1.11 jquery.can u please update ur guide for latest version of jquery
http://www.way2enjoy.com/to...
As I described above, you can replace .live with .on. See the docs on how it's API works.
Dear Ray,
thanks for your reply.i tried with all possible options including on but its not working. used js debugger then also no luck.request you, whenever you get some time, please try once in latest version of jquery for your this post.it will be great help
I also failed to get it working with .on
for later versions of JQuery/JQM and would very much appreciate an update. My coding skills are just not up to it, sorry :)
@ravi: Well, the first step is to see if you can listen to the expand/collapse events. So before even trying to load crap in via AJAX, ensure your event handlers work by checking the console to see if there are fired.
Using on, it should be
$("body").on("expand", "div")
Try that first. The docs for on may be found here: http://api.jquery.com/on/
I do not have plans on updating this post as - well - with ten years of posts I've got a lot of content that would need updating.
So I recommend following the steps I explained above - start simple and ensure you can listen to the event right.
Also, the official docs for jQM show examples: http://api.jquerymobile.com...
Anyone can update this post .please??????
its not working on latest version of Jquery