收集同步后,木偶CompositeView children.findByIndex无法按预期工作 [英] Marionette CompositeView children.findByIndex not working as expected after collection sync

查看:69
本文介绍了收集同步后,木偶CompositeView children.findByIndex无法按预期工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在收集同步之后的 中,我有以下代码:

I have the following code that happens after a collection sync:

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

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

The problem I am running into, is that, after the first sync, the child element is a blank model:

第一次:

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

每次之后:

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

ProductsCollection

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包含productions集合的View.该集合是在layoutview的onShow上获取的

LayoutView that contains the View for the productions collection. The collection is fetched onShow of the 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;
});

推荐答案

我认为您的问题出在ProductsCollection.loadMore方法中.在那里,在您的fetchsuccess回调中,

I think your problem is in the ProductsCollection.loadMore method. There, in the success callback to your fetch you do,

function(collection) { this.add(collection); }

幕后发生的事情是,在调用success回调之前,Backbone首先将对数据运行Collection.set().默认情况下,在set内部,您的数据将被解析为ProductsCollection.parse返回的模型数组,并且如果找到任何新模型,它们将被add编辑到您的现有集合中(请注意,除非您通过{ remove: false }到您的fetch选项,集合中在上一次提取中不是不是的模型将​​被删除.请参见 Collection.set )

What's happening behind the scenes is that before your success callback is invoked, Backbone will first run Collection.set() on your data. By default, inside set your data will be parsed into a array of models returned by ProductsCollection.parse and if any new models are found they will be add'ed to your existing collection (note that unless you pass { remove: false } to your fetch options, models in your collection which are not in your last fetch will be removed. See Collection.set)

因此,当您在loadMore中执行fetch(在第一个fetch之后之后称为)时会发生什么,Backbone首先会从服务器中add所有模型(即从ProductsCollection.parse返回),然后调用fetchsuccess回调,这实际上是最后一个add. add'ing是ProductsCollection实例.不是collection.models而是模型数组,而是具有属性models的Backbone对象,该属性保存原始模型数组.因此,奇怪的输出:

So, what happens when you do the fetch in loadMore, which is called after the first fetch, Backbone will first add all the models from the server (that are returned from ProductsCollection.parse) and then invoke the success callback of your fetch, which, essentially does one last add. And what it's add'ing is the ProductsCollection instance. Not collection.models, an array of models, rather a Backbone object that has a property models that holds a raw array of models. Hence, the strange output:

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

只需删除该success回调(这是不必要的),并且ProductsView的最后一个子视图应该是从返回的最后一个模型呈现的视图.

Simply remove that success callback (which is unnecessary) and the last child view of your ProductsView should be the view rendered from the last model returned.

这篇关于收集同步后,木偶CompositeView children.findByIndex无法按预期工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆