[英]Collection in Backbone.js Not Firing Events
I am trying to implement an action when a change to a model in a given collection is fired, but whenever I try to put a listener on the change
, add
, or remove
events on my collection, no events are fired. 我试图在触发给定集合中的模型更改时实现操作,但每当我尝试将侦听器放在我的集合上的
change
, add
或remove
事件时,都不会触发任何事件。 When I attached a change event to a model's initialize
function (just to test), the change
event was fired successfully. 当我将更改事件附加到模型的
initialize
函数(仅用于测试)时, change
事件已成功触发。 The view below doesn't itself change the code, but I want it to re-render itself whenever a change to the collection has been made. 下面的视图本身不会更改代码,但我希望每当对集合进行更改时它都会重新呈现。 It could be something wrong with my setup, but I want to get your advice.
我的设置可能有问题,但我想得到你的建议。 Below is my code:
以下是我的代码:
contact.js (Model): contact.js(型号):
define([
'jquery',
'underscore',
'backbone'
], function($, _, Backbone){
var ContactModel = Backbone.Model.extend({
urlRoot: '/contacts'
});
return ContactModel;
});
contacts.js (Collection): contacts.js(收藏):
define([
'jquery',
'underscore',
'backbone',
'models/contact'
], function($, _, Backbone, Contact){
var ContactCollection = Backbone.Collection.extend({
url: '/contacts',
model: Contact
});
return ContactCollection;
});
contactlist.js (View): contactlist.js(查看):
define([
'jquery',
'underscore',
'backbone',
'text!templates/contactlist.html',
'collections/contacts'
], function($, _, Backbone, contactListTemplate, Contacts){
var ContactListView = Backbone.View.extend({
el: '.contact-list',
render: function(options) {
var that = this;
var contacts = new Contacts();
contacts.on("add", function() {
console.log('change');
});
contacts.fetch({
success: function(contacts) {
var results = contacts.models;
if (options.query || options.query === '') {
var results = [];
var query = options.query.toUpperCase();
for (var contact in contacts.models) {
if (contacts.models[contact].get('firstname').toUpperCase().indexOf(query) !== -1 ||
contacts.models[contact].get('lastname').toUpperCase().indexOf(query) !== -1 ||
contacts.models[contact].get('email').toUpperCase().indexOf(query) !== -1 ||
contacts.models[contact].get('phonenumber').toString().toUpperCase().indexOf(query) !== -1)
{
results.push(contacts.models[contact]);
}
}
options.idclicked = null;
}
if (!options.idclicked && results[0]) {
options.idclicked = results[0].get('id');
Backbone.history.navigate('/contacts/' + results[0].get('id'), {trigger: true});
}
var template = _.template(contactListTemplate, {contacts: results, idclicked: options.idclicked});
that.$el.html(template);
$(document).ready(function() {
$('.contact-list').scrollTop(options.scrolled);
});
}
});
},
events: {
'click .contact': 'clickContact'
},
clickContact: function (ev) {
$('.contact-clicked').removeClass('contact-clicked').addClass('contact');
$(ev.currentTarget).addClass('contact-clicked').removeClass('contact');
window.location.replace($(ev.currentTarget).children('a').attr('href'));
}
});
return ContactListView;
});
Since Backbone 1.0 ( change log ), the answer to this question isn't 100% accurate anymore. 自从Backbone 1.0( 更改日志 )以来,这个问题的答案不再是100%准确的。
In Backbone 1.0+, you'll have to pass { reset: true }
into the .fetch()
method if you want the reset
event to fire. 在Backbone 1.0+中,如果要
.fetch()
reset
事件,则必须将{ reset: true }
传递给.fetch()
方法。 See below. 见下文。
Calling fetch
on a collection will now trigger a 3 different events: 在集合上调用
fetch
现在将触发3个不同的事件:
collection.fetch(); //triggers the following events
request
: Triggered before the ajax request is made request
:在发出ajax请求之前触发 add
: (multiple times) this event will be triggered multiple times as each item in the data is added to the collection. add
:(多次)当数据中的每个项目添加到集合中时,将多次触发此事件。 sync
: Triggered after data on the collection is synced with the data provider (data added to collection, ajax request completed) sync
:在集合上的数据与数据提供程序同步后触发(数据已添加到集合,ajax请求已完成) To revert to the old style of backbone events, you need to call 要恢复到旧式的骨干事件,您需要调用
collection.fetch({ reset: true }); //triggers the following events
request
: Triggered before the ajax request is made request
:在发出ajax请求之前触发 reset
: Triggered when all data is placed into the collection. reset
:将所有数据放入集合时触发。 sync
: Triggered after data on the collection is synced with the data provider (data added to collection, ajax request completed) sync
:在集合上的数据与数据提供程序同步后触发(数据已添加到集合,ajax请求已完成) The best way to quickly see what events that your collection is triggering , is to bind to the all
event and log the arguments: 快速查看集合触发的事件的最佳方法是绑定到
all
事件并记录参数:
collection.on('all', function() {
console.log(arguments);
});
When running fetch()
, the collection will trigger it's reset
event, not add
. 运行
fetch()
,集合将触发它的reset
事件,而不是add
。
contacts.on("reset", function() {
console.log('reset');
});
That will run as soon as the fetch completes, before your success
callback. 在
success
回调之前,一旦获取完成,它就会运行。
change
runs when the model itself has attributes changed, which you don't do anywhere in the code you posted. 当模型本身更改了属性时,
change
将运行,您在发布的代码中不会执行任何操作。
Also generally I wouldn't access .models
directly. 通常我也不会直接访问
.models
。 I'd do this: 我这样做:
var results = contacts.toArray();
if (options.query || options.query === ''){
results = contacts.filter(function(contact){
return _.any(['firstname', 'lastname', 'email', 'phonenumber'], function(attr){
return contact.get(attr).toString().toUpperCase().indexOf(query) !== -1;
});
});
// ...
As it is now, you create the collection when you render. 就像现在一样,您在渲染时创建集合。 This is not a good idea because ideally you would want to be able to render again without fetching all of the data again.
这不是一个好主意,因为理想情况下,您希望能够再次渲染而无需再次获取所有数据。
I would move the collection creation logic into the view's initialize
function like this: 我将集合创建逻辑移动到视图的
initialize
函数中,如下所示:
initialize: function(options){
this.collection = new Contacts();
this.collection.on('reset add remove', this.render, this);
}
That way, as the collection changes, render is automatically triggered. 这样,随着集合的更改,渲染会自动触发。 This is complicated by your
options
, so I would try to change how you pass those arguments in. Maybe add a 'setOptions' function that saves the options to use while rendering. 你的
options
很复杂,所以我会尝试改变你传递这些参数的方式。也许添加一个'setOptions'函数来保存渲染时使用的选项。 Ideally render
will re-render the page identically to how it was before the call, it doesn't normally have arguments. 理想情况下,
render
将重新呈现页面与调用之前的相同,它通常不具有参数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.