Reputation: 13347
It's obvious that this is a timing issue. I have a jQuery mobile app that I am developing. I am doing the standard method of appending items to a listview. Then calling refresh
after the items are appended. Yes I have jQuery and jQuery mobile in the head of the html and yes I am using the 'pageinit'
event instead of $(document).ready()
. Here are the sources:
The JS
GetApps: function () {
$('#manage-apps-list').empty();
$.get('../../../config.xml', function (data) {
$(data).find('app').each(function () {
var $this = {};
$this = $(this);
$('#manage-apps-list').append(
$('<li/>').append(
$('<a/>').attr('href', "#app-settings").attr('data-id', $this.find('id').text()).html($this.find('title').text()).off('click').on('click', function () {GetAppDetail($(this).attr('data-id'));})
)
);
});
});
$('#manage-apps-list').listview('refresh');
}
The HTML
<div id="manage-apps" data-role="page" data-theme="d">
<div data-role="content">
<a href="#settings" data-role="button" data-mini="true" data-inline="true">Back</a>
<h2>Manage Apps</h2>
<ul id="manage-apps-list" data-role="listview" data-inset="true"></ul>
</div>
</div>
This is not the initial page to be seen, but a sub-page. Here is the result:
I have done this many, many times in my apps, and it always works without issue. I am even using the same versions of $
and $.mobile
I have seen many other questions about this on SO, but they all are missing the call to refresh
...
Upvotes: 0
Views: 163
Reputation: 11381
You're right. It IS a timing issue. Your refresh
method isn't waiting for the list to finish up its append work. So, a slight restructure of your get
method is needed :
GetApps: function () {
$('#manage-apps-list').empty();
$.get('../../../config.xml', function (data) {
//set up an array for adding li to it.
var li = [];
//a temporary element to store "li"
var $li;
$(data).find('app').each(function () {
var $this = $(this);
//add the li HTML element to a vairable
$li = $('<li/>').append(
//you can also create the anchor tag like this - looks nicer :)
$('<a/>', {
"href": "#app-settings",
"data-id": $this.find('id').text(),
"html": $this.find('title').text()
}));
//add this $li to the main array of li
li.push($li);
});
//append li [] to ul
$('#manage-apps-list').append(li).promise().done(function () {
//wait for list to be added - thats why you wait for done() event in promise()
//add the click events to this - event delegation - this way your click event is added only once
$(this).on('click', 'a', function (e) {
//to prevent default click - just in case
e.preventDefault();
GetAppDetail($(this).attr('data-id'));
});
//then refresh
$(this).listview().listview("refresh");
});
});
}
each
. I pushed that to an array and appended it at the end. So you'll have only one append overall.click
event every single time for all the <a>
tags. This is the behaviour which onclick
did. Binding event handlers repeatedly is BAD. Thats why even delegation is brought in now. <a>
tag)refresh
wait for the append
to complete, you can add promise()
to the append
and wait for it to be done()
. Here's a prototype of what I'm talking abt : http://jsfiddle.net/hungerpain/TdHXL/
Upvotes: 2