开发者

Backbone.js backed list not being refreshed by jQuery mobile (listview(‘refresh’))

I’m trying to add sort options to a JQM list which is backed by a backbone.js collection. I’m able to sort the collection (through the collection’s view) and rerender the list, but JQM isn’t refreshing the list.

I’ve been searching and I found several questions similar to mine (problems getting the JQM listview to refresh) but I’ve been unable to get it to work.

I’ve tried calling $(‘#list’).listview(‘refresh’) and $(‘#list-page’).page() etc. to no avail. I suspect that Perhaps I’m calling the refresh method in the wrong place (to early), but I’m not sure where else I should put it (I’m just starting out with backbone).

Here’s the markup and js.

HTML:

<div data-role="page" id="Main">
<div data-role="header"><h1>Main Page</h1></div>
<div data-role="content">   
        <ul data-role="listview">
            <li><a href="#Page1">Page 1</a></li>
        </ul> 
</div>
<div data-role="footer"><h4>Footer</h4></div>
</div>

<div data-role="page" id="Page1">
  <div data-role="header">
  <a href="#Main" data-role="back" data-icon="back">Back</a>
  <h1>Items</h1><a href="#dvItemSort" >Sort</a></div>
  <div data-role="content">
    <div id="dvTest">
        <ul id="ItemList" data-role="listview"  data-filter="true"></ul>
    </div>
  </div><div  data-role="footer"><h4>Footer</h4></div></div>

  <div data-role="page" id="dvItemSort">
  <div data-role="header"><h4>Sort</h4></div>
      <a href="#Page1" type="button" 
       name="btnSortByID" id="btnSortByID">ID</a>
      <a href="#Page1" type="button" 
       name="btnSortByName" id="btnSortByName">Name </a>
  </div>

Javascript:

  $(function () {

    window.Item = Backbone.Model.extend({
    ID: null,
    Name: null
});

window.ItemList = Backbone.Collection.extend({
    model: Item
});

window.items = new ItemList;
window.ItemView = Backbone.View.extend({
    tagName: 'li',

    initialize: function () {
        this.model.bind('change', this.render, this);
    },

    render: function () {
        $(this.el).html('<a>' + this.model.get('Name') + '</a>');
        return this;
    }
});

window.ItemListView = Backbone.View.extend({

    el: $('body'),

    _ItemViews: {},

     events: {
        "click #btnSortByID": "sortByID",
        "click #btnSortByName": "sortByName"
    },

    initialize: function () {
        items.bind('add', this.add, this);
        items.bind('reset', this.render, this);
    },

    render: function () {

        $('#ItemList').empty();

        _.each(items.models, function (item, idx) {
            $('#ItemList').append(this._ItemViews[item.get('ID')].render().el);
        }, this);
        
         $('#ItemList').listview('refresh'); //not wo开发者_JAVA百科rking
        // $('#ItemList').listview(); 
        // $('#Page1').trigger('create');
         // $('#Page1').page(); //also doesn't work
    },


    add: function (item) {
        var view = new ItemView({ model: item });
        this._ItemViews[item.get('ID')] = view;
        this.$('#ItemList').append(view.render().el);

    },

    sortByName: function () {
        items.comparator = function (item) { return item.get('Name'); };
        items.sort();
    },

    sortByID: function () {
    
        items.comparator = function (item) { return item.get('ID'); };
        items.sort();
    }
});

window.itemListView = new ItemListView;

window.AppView = Backbone.View.extend({ 

    el: $('body'),

    initialize: function () {

        items.add([{ID: 1, Name: 'Foo 1'}, {ID:2, Name: 'Bar 2'}]);

    },
});

window.App = new AppView; 

});

EDIT: I realized that the first line of html markup I posted wasn't displaying in my post so I pushed it down a line.

EDIT 2: Here's a link to a jsfiddle of the code http://jsfiddle.net/8vtyr/2/

EDIT 3 Looking at the resulting markup, it seems like JQM adds some of the classes to the list items. I tried adding them manually using a flag to determine whether the list was being reRendered as a result of a sort and the list then displays correctly.

However, besides being somewhat of an ugly solution, more importantly my backbone events on the “item” view no longer fire (in the code example I posted I didn’t put the code for the events because I was trying to keep it as relevant as possible).

EDIT 4 I sort of got it working by clearing my cache of views and recreating them. I posted my answer below.

EDIT 5 I updated my answer with what i think is a better answer.


I'm not sure if this should be its own answer or not (i did look through the FAQ a bit), so for now I’m just updating my previous answer.

I have now found a better way to sort the list using my cached views. Essentially the trick is to sort the collection, detach the elements from the DOM and then reattach them. So

The code now would be

 $list = $('#ItemList')

 $('li', $list ).detach();
 var frag = document.createDocumentFragment();
 var view;
    _.each(item.models, function (mdl) {
    view = this._ItemViews[item.get('ID')];
        frag.appendChild(view.el);
    },this);

   $list.append(frag);

OLD ANSWER

I sort of solved the problem. I was examing the rendered elements and I noticed that when the elements were “rerendered” (after the sort) they lost the event handlers (I checked in firebug). So I decided to clear my cache of views and recreate them. This seems to do the trick, though I’m not really sure why exactly.

For the code:

Instead of:

  $('#ItemList').empty();
    _.each(items.models, function (item, idx) {
        $('#ItemList').append(this._ItemViews[item.get('ID')].render().el);
    }, this);
     $('#ItemList').listview('refresh'); //not working

I clear the view cache and recreate the views.

  $('#ItemList').empty();
        this._ItemViews = {};
        _.each(items.models, function (item, idx) {
            var view = new ItemView({ model: item  });
            this._ItemViews[item.get('ID')] = view;
            this.$('#ItemList').append(view.render().el)           
        }, this);
        $('#ItemList').listview('refresh'); //works now

I think it would probably be better if I didn’t need to regenerate the cache, but at least this is a working solution and if I don't get a better answer then I'll just accept this one.


I had some luck in solving this, but the reason remains obscure to me.

Basically, at the top of my render view after establishing the html() of my element, I call listview(). Then, any further items I might add to a list call listview('refresh').

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜