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 ...
After wading around in the event system, I concluded for now that if you set
preventDefault()
once you are stuck with it forever. Based on the solution of charlietfl I added code to make the visual impact minimal, maybe there is also a way to prevent the GUI from refreshing for the 20ms to make it fully unnoticable.I'm still searching for a solution that resets the event to its previous state, though.
When
expand
/collapse
events are triggered, jQM adds several classes to show/hide contents as well as update collapsible button/header.In this case,
event.preventDefault()
isn't going to prevent event(s) from bubbling and stop them from executing. Thus you need to useevent.stopImmediatePropagation()
to stopexpand
event once header is clicked.When a collapsible is collapsed, it has a class
ui-collapsible-collapsed
and once expanded, the class is removed. Therefore, whencollapse
is triggered, it works normally without interruption.I'm not intimately familiar with JQM but my first thought was empty the list before sending for more data....which seems to prevent it expanding.
DEMO - without ajax