Коллекция в позвоночнике.js не запускает события
Я пытаюсь реализовать действие, когда происходит изменение модели в данной коллекции, но всякий раз, когда я пытаюсь поставить слушателя на change
, add
, или remove
события в моей коллекции, никакие события не запускаются. Когда я прикрепил событие изменения к функции модели initialize
(просто для проверки), событие change
было успешно запущено. Приведенный ниже вид сам по себе не изменяет код, но я хочу, чтобы он перерисовывался всякий раз, когда вносятся изменения в коллекцию. Это может быть что-то не так с моей установки, но я хочу получить ваш совет. Ниже приведен мой код:
Контакт.js (Модель):
define([
'jquery',
'underscore',
'backbone'
], function($, _, Backbone){
var ContactModel = Backbone.Model.extend({
urlRoot: '/contacts'
});
return ContactModel;
});
Контакты.js (коллекция):
define([
'jquery',
'underscore',
'backbone',
'models/contact'
], function($, _, Backbone, Contact){
var ContactCollection = Backbone.Collection.extend({
url: '/contacts',
model: Contact
});
return ContactCollection;
});
Список контактов.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;
});
2 ответа:
При запуске
fetch()
коллекция инициирует событиеreset
, а неadd
.contacts.on("reset", function() { console.log('reset'); });
, который будет запущен сразу после завершения выборки, до вашего обратного вызова
success
.
change
запускается, когда атрибуты самой модели изменены, чего вы не делаете нигде в опубликованном коде.Также обычно я бы не обращался к
.models
напрямую. Я бы сделал так: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; }); }); // ...
Обновление
Как и сейчас, вы создаете коллекцию при рендеринге. Это не очень хорошая идея потому что в идеале вы хотели бы иметь возможность отрисовывать снова, не извлекая все данные снова.
Я бы переместил логику создания коллекции в функцию вида
initialize
следующим образом:initialize: function(options){ this.collection = new Contacts(); this.collection.on('reset add remove', this.render, this); }
Таким образом, при изменении коллекции автоматически запускается рендеринг. Это осложняется вашим
options
, поэтому я бы попытался изменить то, как вы передаете эти аргументы. Может быть, добавить функцию setOptions, которая сохраняет параметры для использования во время рендеринга. В идеалеrender
будет повторно визуализировать страница идентична тому, как это было до вызова, она обычно не имеет аргументов.
Начиная с Backbone 1.0 (change log ), ответ на этот вопрос больше не является точным на 100%.
В Backbone 1.0+ вам придется передать
{ reset: true }
в метод.fetch()
, Если вы хотите, чтобы событиеreset
сработало. Увидеть ниже.Вызов
fetch
коллекции теперь вызовет 3 различных события:
collection.fetch(); //triggers the following events
request
: срабатывает до выполнения запроса ajaxadd
: (несколько раз) это событие будет вызвано несколько раз, как каждый пункт в данные добавляются в коллекцию.sync
: срабатывает после синхронизации данных о коллекции с поставщик данных (данные добавлены в коллекцию, ajax-запрос завершен)
Чтобы вернуться к старому стилю магистральных событий, вам нужно вызвать
collection.fetch({ reset: true }); //triggers the following events
request
: срабатывает до выполнения запроса ajaxreset
: срабатывает, когда все данные помещаются в коллекцию.sync
: срабатывает после синхронизации данных по коллекции с поставщик данных (данные добавлены в коллекцию, ajax-запрос завершен)
Лучший способ быстро увидеть, какие события запускает ваша коллекция , это привязать к событию
all
и записать аргументы:collection.on('all', function() { console.log(arguments); });