I want to integrate a collapsible in my jQM app (1.3.2) that works as follows:
- It starts collapsed.
- On click it starts to fetch listitems for the collapsible from the server. The collapsible stays closed, a load icon may be spinning.
- After all elements are loaded and the listview refreshed and ready, the collapsible expands.
- If you click it again, it closes directly without delay, and starts from 1.
My initial idea was to grab the expand
event and prevent its propagation. When loading is finished I de-register my custom event handler to turn the collapsible back to normal, and finally triggering the expand event from JavaScript to open.
The problem is that this works for the first round, but afterwards the collapsible opens anyway. Consider this example (also in jsfiddle):
<div data-role="collapsible" id="c">
<h2>Collapse</h2>
<ul data-role="listview" id="lv">
<li>You don't see me!</li>
</ul>
</div>
<a href="#" data-role="button" onClick="$('#c').off('expand', stop)">
Unlock the collapsible
</a>
<a href="#" data-role="button" onClick="$('#c').on('expand', stop)">
Lock the collapsible
</a>
JavaScript:
var stop = function(event) {
alert('Locked!');
event.preventDefault();
}
// executed after the element is created ...
$('#c').on('expand', stop)
Here, if you click the collapsible after loading, it stays closed (good). When you click unlock, it opens and no alert is shown (good). If you lock it again it shows the alert (good) but opens anyways (bad).
Can anyone enlighten me what I am doing wrong? There seems to be side-effects from unlocking that I cannot see. There are several similar questions here, but most are happy with just preventing the expansion without turning it back on again.
So my question is: What is the best way to delay the expansion of a collapsible reliably?
Edit: I added another example that integrates the listview logic and also shows this error. jsFiddle is here. I also moved to .one()
to make the de-registering more traceable.
New JavaScript:
var stop_n_load = function (event) {
alert('stop opening! (or at least try to ...)');
// try to stop the expanding by stopping the event
event.preventDefault();
// Do some work that takes time and trigger expand afterwards ...
setTimeout(function (e) {
dd = new Date();
$('#lv').empty();
$('#lv').append("<li><a href='#'>Item A ("+dd+")</a></li>");
$('#lv').append("<li><a href='#'>Item B ("+dd+")</a></li>");
$('#lv').listview('refresh');
// when done, start expanding without this handler (was register only once)
$('#c').trigger('expand');
// for the next collapse register stop_n_load again
$('#c').one('collapse', reset);
}, 2000);
};
var reset = function (event) {
$('#c').one('expand', stop_n_load);
};
$('#c').one('expand', stop_n_load);
On the first expansion it works as expected, it first updates and then opens. On the second run it opens without waiting, you can see the timestamp updating later, so the event is called properly.
There seems to be a problem with .preventDefault()
I don't understand ...