SnareChops
SnareChops

Reputation: 13347

jquery mobile listview refresh exceptions (probably timing)

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:

enter image description here

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

Answers (1)

krishwader
krishwader

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");    
      });
   });
 }

What I changed in your code

  1. You were appending as you got the data in each. I pushed that to an array and appended it at the end. So you'll have only one append overall.
  2. You were adding 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.
  3. Changed a little bit of element sturcturing. (for example the <a> tag)
  4. Important Finally, to make the 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

Related Questions