Marionette CompositeView children.findByIndex 集合同步后未按预期工作
Marionette CompositeView children.findByIndex not working as expected after 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
元素是一个空白模型:
第一次:
Object {id: "5-vp39kv3uiigxecdi", size: 26, price: "9.84", face: "( ⚆ _ ⚆ )"}
每次之后:
Object {length: 40, models: Array[41], _byId: Object, _listeningTo: Object, _listenId: "l14"…}
产品系列
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;
});
包含产品集合视图的布局视图。该集合是在布局视图的显示上获取的
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;
});
广告视图:
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
方法中。在那里,在 success
回调到你的 fetch
你做的,
function(collection) { this.add(collection); }
幕后发生的事情是,在调用 success
回调之前,Backbone 将首先 运行 Collection.set()
处理您的数据。默认情况下,在 set
中,您的数据将被解析为由 ProductsCollection.parse
返回的模型数组,如果发现任何新模型,它们将被 add
编辑到您现有的 collection(请注意,除非您将 { remove: false }
传递给您的 fetch
选项,否则您 collection 中的模型在您上次获取时 而不是 将被删除。参见 Collection.set
)
那么,当您在 loadMore
中执行 fetch
时会发生什么,这称为 在 第一个 fetch
、Backbone 将首先 add
服务器中的所有模型(从 ProductsCollection.parse
返回),然后调用 fetch
的 success
回调,这实际上是最后一个add
。 add
是 ProductsCollection
实例。不是 collection.models
,一个模型数组,而是一个 Backbone object,它有一个 属性 models
,其中包含一个原始模型数组。因此,奇怪的输出:
Object {length: 40, models: Array[41], _byId: Object, _listeningTo: Object,
_listenId: "l14"…}
只需删除 success
回调(这是不必要的),您 ProductsView
的最后一个 child 视图应该是从返回的最后一个模型呈现的视图。
我有以下代码发生在集合同步之后:
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"…}
产品系列
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;
});
包含产品集合视图的布局视图。该集合是在布局视图的显示上获取的
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;
});
广告视图:
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
方法中。在那里,在 success
回调到你的 fetch
你做的,
function(collection) { this.add(collection); }
幕后发生的事情是,在调用 success
回调之前,Backbone 将首先 运行 Collection.set()
处理您的数据。默认情况下,在 set
中,您的数据将被解析为由 ProductsCollection.parse
返回的模型数组,如果发现任何新模型,它们将被 add
编辑到您现有的 collection(请注意,除非您将 { remove: false }
传递给您的 fetch
选项,否则您 collection 中的模型在您上次获取时 而不是 将被删除。参见 Collection.set
)
那么,当您在 loadMore
中执行 fetch
时会发生什么,这称为 在 第一个 fetch
、Backbone 将首先 add
服务器中的所有模型(从 ProductsCollection.parse
返回),然后调用 fetch
的 success
回调,这实际上是最后一个add
。 add
是 ProductsCollection
实例。不是 collection.models
,一个模型数组,而是一个 Backbone object,它有一个 属性 models
,其中包含一个原始模型数组。因此,奇怪的输出:
Object {length: 40, models: Array[41], _byId: Object, _listeningTo: Object,
_listenId: "l14"…}
只需删除 success
回调(这是不必要的),您 ProductsView
的最后一个 child 视图应该是从返回的最后一个模型呈现的视图。