Backbone.js: After doing Fetch(), render only the new models

自古美人都是妖i 提交于 2019-12-23 10:10:37

问题


I have a Collection App.listingList where subsequent fetch() are called with add:true.

App.listingList.fetch({
        data: {some:data},
        processData: true,
        add: true
});

Problem: How can the newly added models have their views rendered, without re-rendering the views of the existing models. This means I cannot do:

this.collection.each( function(listing, index) {
    new ListingMarkerView({ model:listing }).render();
}, this);

Attempt #1

Rendering the View on the collection's add event, I cannot figure out a way to access the new models to render

ListingListView = Backbone.View.extend({

    initialize: function() {
        this.collection.bind('add', this.renderNew, this);
    },

    render: function() {
        console.log('render ListingListView');
        this.collection.each( function(listing, index) {
            new ListingMarkerView({ model:listing }).render();
        }, this);
        return this;
    },

    renderNew: function() {
        // How do I grab the new models?
        new ListingMarkerView({ model:listing }).render(); // wont work
        return this;
    }
});

Attempt #2

I tried having a second Collection to do the subsequent fetch on, and compare the models of both collections using underscore.js's _.without(), but the array returned still contains the elements found in the 2nd array passed as the parameter. Using _difference() also returned the same array passed as the first array.

App.listingListNew.fetch({
        data: {some:data},
        processData: true,
        success: function() {
            console.log(App.listingListNew.models);
            console.log(App.listingList.models);
            console.log(_.without(App.listingListNew.models, App.listingList.models));
            console.log(_.difference(App.listingListNew.models, App.listingList.models));
        }
});

console.log Output

Since I passed in 2 identical arrays into _.difference() and _.without(), the output should be []. But it isnt :/ Maybe because cid is different, so every one of them are treated as unique?


回答1:


When you do a collection.bind('add', this.renderNew, this); it automatically passes the added model to your method as an argument.

Include the argument in your method and you should have access to the new model.

renderNew: function(newModel) {
    new ListingMarkerView({ model:newModel }).render();
    return this;
}



回答2:


I know this is an old question, but I was having the same issue and came across this response so I thought I'd add an alternate approach. I'm not sure how efficient it is, but it works. I'm using this to support an infinite scroll feature.

I'm using Backbone 1.2.1, so in the collection fetch, I'm using remove:false instead of the deprecated add:true per the docs here: http://backbonejs.org/#Collection-fetch

The basic approach is to set a rendered attribute to true on each item in the collection when first rendered, then use that to ignore previously rendered items on subsequent fetches.

Model and Collection:

MyApp.Item = Backbone.Model.extend({});

MyApp.ItemList = Backbone.Collection.extend({
model: MyApp.Item,
    url: '/api/item/',
    parse : function(response){
        if (response.stat) {
            return _.map(response.content, function(model, id) {
                model.id = id;
                return model;
            });
        }
    }
});

Views:

MyApp.ItemListView = Backbone.View.extend({
    tagName: 'ul',
    className: 'item-list',
    render: function() {
        this.collection.each(function(item){
            //don't render items that have already been rendered!
            if (!item.rendered) {
                var itemListDetailView = new MyApp.ItemListDetailView({model: item});
                this.$el.append(itemListDetailView.render().el);
                item.rendered = true;
            }
        }, this)
        return this;
    }
});

MyApp.ItemListDetailView = Backbone.View.extend({
    tagName: 'li',
    className: 'item-list-detail',
    render: function() {
        $(this.el).html( '<div class="item-title">' + this.model.get('title') + '</div>');
        return this;
    }
});

Fetch function:

MyApp.loadMyItems = function () {
    MyApp.gettingData = true;  //flag for infinite scroll
    MyApp.myItems.fetch({
        traditional: true,
        remove:false,
        data: {
            u_id: MyApp.User.id,
            order: 'create_date:desc',
            start: MyApp.myItems.length,
            num_items: 10
        },
        success: function(){
           MyApp.gettingData = false; //flag for infinite scroll
           MyApp.myItemsView.render();
        }
    });
};

Calling:

//on initial page load
MyApp.myItems = new MyApp.ItemsCollection();
MyApp.myItemsView = new MyApp.ItemListView({
                            collection: MyApp.myItems, 
                            el: $('#my-items') 
                         });
MyApp.loadMyItems();

//infinite scroll
$('#items .infinite-scroll').on('loadmore', function () {
    if (!MyApp.gettingData) {
        MyApp.loadMyItems();
    } 
});


来源:https://stackoverflow.com/questions/12655913/backbone-js-after-doing-fetch-render-only-the-new-models

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!