收集同步后,Marionette CompositeView children.findByIndex无法按预期工作

时间:2015-07-10 18:17:36

标签: marionette

我有以下代码在集合同步后发生

    adGeneration: function() {
        var child = this.children.findByIndex(this.children.length - 1);
        console.log(child.model.toJSON());
        eventer.trigger('generate:new:ad', child);
    },

我遇到的问题是,在第一次同步后,child元素是一个空白模型:

第一次:

Object {id: "5-vp39kv3uiigxecdi", size: 26, price: "9.84", face: "( ⚆ _ ⚆ )"}

每次之后:

Object {length: 40, models: Array[41], _byId: Object, _listeningTo: Object, _listenId: "l14"…}

ProductsCollection

define(["backbone", "lodash", "fonts/products/model", "eventer"],
function(Backbone, _, ProductModel, eventer) {
    'use strict';

    var ProductsCollection = Backbone.Collection.extend({
        model: ProductModel,

        sort_key: 'price',

        url: '/api/products',

        offset: 0,

        initialize: function() {
            this.listenTo(eventer, 'fetch:more:products', this.loadMore, this);
        },

        comparator: function(item) {
            return item.get(this.sort_key);
        },

        sortByKey: function(field) {
            this.sort_key = field;
            this.sort();
        },

        parse: function(data) {
            return _.chain(data)
                    .filter(function(item) {
                        if(item.id) {
                            return item;
                        }
                    })
                    .map(function(item){
                        item.price = this.formatCurrency(item.price);

                        return item;
                    }.bind(this))
                    .value();
        },

        formatCurrency: function(total) {
            return (total/100).toFixed(2);
        },

        loadMore: function() {
            this.offset += 1;
            this.fetch({
                data: {
                    limit: 20,
                    skip: this.offset
                },
                remove: false,
                success: function(collection) {
                    this.add(collection);
                }.bind(this)
            });
        }
    });

    return ProductsCollection;

});

包含制作集合视图的LayoutView。该集合是在layoutview的显示中获取的

define(["marionette", "lodash", "text!fonts/template.html",
"fonts/controls/view", "fonts/products/view", "fonts/products/collection", "eventer"],
function(Marionette, _, templateHTML, ControlsView, ProductsView,
    ProductsCollection, eventer) {
    'use strict';

    var FontsView = Marionette.LayoutView.extend({

        regions: {
            controls: '#controls',
            products: '#products-list'
        },

        template: _.template(templateHTML),

        initialize: function() {
            this._controlsView = new ControlsView();
            this._productsView = new ProductsView({
                collection: new ProductsCollection({
                    reorderOnSort: false,
                    sort: false
                })
            });

            this.listenTo(this._productsView.collection, 'sync', this.loading, this);
            this.listenTo(eventer, 'fetch:more:products', this.loading, this);
            this.listenTo(eventer, 'products:end', this.productsEnd, this);
        },

        onRender: function() {
            this.getRegion('controls').show(this._controlsView);
            this.getRegion('products').show(this._productsView);
            this.loading();
        },

        onShow: function() {
            this._productsView.collection.fetch({
                data: {
                    limit: 20
                }
            })
        },

        productsEnd: function() {
            this.loading();
            this.$el.find('#loading').html("~ end of catalogue ~")
        },

        loading: function() {
            var toggle = this.$el.find('#loading').is(':hidden');
            this.$el.find('#loading').toggle(toggle);
        }
    });

    return FontsView;

});

AdsView:

define(["marionette", "lodash", "text!ads/template.html", "eventer"],
function(Marionette, _, templateHTML, eventer) {
    'use strict';

    var AdsView = Marionette.ItemView.extend({
        template: _.template(templateHTML),

        ui: {
            ad: '.ad'
        },

        initialize: function() {
            this.listenTo(eventer, 'generate:new:ad', this.generateNewAd, this);
        },

        onShow: function() {
            // Set add image onShow
            this.ui.ad.prop('src', '/ad/' + this.randomNumber());
        },

        generateNewAd: function(childView) {
            var newAd = this.ui.ad.clone(),
                element = childView.$el,
                elementId = childView.model.get("id");

            newAd.prop('src', '/ad/' + this.randomNumber());

            $("#" + elementId).after(newAd);
        },

        randomNumber: function() {
            return Math.floor(Math.random()*1000);
        },

        setUpAd: function() {
            this.ui.ad.prop('src', '/ad/' + this.randomNumber());
        }
    });

    return AdsView;
});

1 个答案:

答案 0 :(得分:2)

我认为您的问题出在ProductsCollection.loadMore方法中。在您success的{​​{1}}回调中,

fetch

幕后发生的事情是,在调用function(collection) { this.add(collection); } 回调之前,Backbone将首先对您的数据运行success。默认情况下,在Collection.set()内,您的数据将被解析为set返回的模型数组,如果找到任何新模型,它们将ProductsCollection.parse添加到您现有的集合中(请注意,除非您将add传递到{ remove: false }个选项,否则系统会删除您上次提取中的模型。请参阅Collection.set)< / p>

那么,当您在fetch中执行fetch时会发生什么,在第一个loadMore之后称为,Backbone将首先fetch来自服务器的所有模型(从add返回)然后调用ProductsCollection.parse的{​​{1}}回调,这基本上是最后一次success。它fetch实例的add是什么。不是add,一个模型数组,而是一个具有属性ProductsCollection的Backbone对象,它包含一个原始的模型数组。因此,奇怪的输出:

collection.models

只需删除models回调(这是不必要的),Object {length: 40, models: Array[41], _byId: Object, _listeningTo: Object, _listenId: "l14"…} 的最后一个子视图应该是从最后返回的模型中呈现的视图。