2

我试图在给定集合中的模型更改被触发时实现一个动作,但是每当我尝试在我的集合上的 、 或 事件上放置一个侦听changeaddremove,都不会触发任何事件。当我将更改事件附加到模型的initialize函数(只是为了测试)时,该change事件被成功触发。下面的视图本身不会更改代码,但我希望它在对集合进行更改时重新呈现自己。我的设置可能有问题,但我想听听您的建议。下面是我的代码:

contact.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;

});

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;

});
4

2 回答 2

9

自 Backbone 1.0(更改日志)以来,这个问题的答案不再是 100% 准确。

在 Backbone 1.0+ 中,如果要触发事件,则必须{ reset: true }传入方法。见下文。.fetch()reset

调用fetch集合现在将触发 3 个不同的事件:


collection.fetch(); //triggers the following events
  1. request:在发出ajax请求之前触发
  2. add:(多次)随着数据中的每个项目被添加到集合中,此事件将被多次触发。
  3. sync: 集合上的数据与数据提供者同步后触发(数据添加到集合,ajax 请求完成)

要恢复到旧式主干事件,您需要调用

collection.fetch({ reset: true }); //triggers the following events
  1. request:在发出ajax请求之前触发
  2. reset:当所有数据都放入集合时触发。
  3. sync: 集合上的数据与数据提供者同步后触发(数据添加到集合,ajax 请求完成)

快速查看您的集合正在触发哪些事件的最佳方法是绑定到all事件并记录参数:

collection.on('all', function() {
    console.log(arguments);
});
于 2013-04-07T21:56:13.350 回答
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,将重新呈现与调用前相同的页面,它通常没有参数。

于 2012-12-30T20:58:06.517 回答