嵌套集合中的模型更改事件未按预期触发

Pal*_*son 9 javascript backbone.js

我正在尝试在我的第一个"真正的"应用程序中使用backbone.js,我需要一些帮助来调试为什么某些模型更改事件没有像我期望的那样触发.

如果我从服务器创建一个JSON 数组的集合,然后按设定的时间间隔获取()它,如果集合中的单个模型发生了变化,我不会收到通知.主干文档建议应生成此类通知.我似乎得到的只是每次获取的刷新通知,这是没用的.OTOH,如果我从服务器的JSON 对象创建模型,然后按设定的时间间隔获取()模型,我会在属性更改时收到更改通知.有任何想法吗?

细节

/ employees/{username}/tasks中的我的Web服务返回一个JSON任务对象数组,每个任务对象都嵌套一个子任务对象的JSON数组.例如,

[{
  "id":45002,
  "name":"Open Dining Room",
  "subtasks":[
    {"id":1,"status":"YELLOW","name":"Clean all tables"},
    {"id":2,"status":"RED","name":"Clean main floor"},
    {"id":3,"status":"RED","name":"Stock condiments"},
    {"id":4,"status":"YELLOW","name":"Check / replenish trays"}
  ]
},{
  "id":47003,
  "name":"Open Registers",
  "subtasks":[
    {"id":1,"status":"YELLOW","name":"Turn on all terminals"},
    {"id":2,"status":"YELLOW","name":"Balance out cash trays"},
    {"id":3,"status":"YELLOW","name":"Check in promo codes"},
    {"id":4,"status":"YELLOW","name":"Check register promo placards"}
  ]
}]
Run Code Online (Sandbox Code Playgroud)

另一个Web服务允许我更改特定任务中特定子任务的状态,如下所示:/ tasks/45002/subtasks/1/status/red [旁边 - 我打算将其更改为基于HTTP的HTTP服务,但目前的实现更容易调试]

我的JS应用程序中有以下类:

子任务模型和子任务集合

var Subtask = Backbone.Model.extend({});

var SubtaskCollection = Backbone.Collection.extend({
  model: Subtask
});
Run Code Online (Sandbox Code Playgroud)

具有子任务集合的嵌套实例的任务模型

var Task = Backbone.Model.extend({
  initialize: function() {

    // each Task has a reference to a collection of Subtasks
    this.subtasks = new SubtaskCollection(this.get("subtasks"));

    // status of each Task is based on the status of its Subtasks
    this.update_status();

  },
  ...
});

var TaskCollection = Backbone.Collection.extend({
  model: Task 
});
Run Code Online (Sandbox Code Playgroud)

任务视图用于呈现项目并侦听模型的更改事件

var TaskView = Backbone.View.extend({

  tagName:  "li",

  template: $("#TaskTemplate").template(),

  initialize: function() {
    _.bindAll(this, "on_change", "render");
    this.model.bind("change", this.on_change);
  },

  ...

  on_change: function(e) {
    alert("task model changed!");
  }

});
Run Code Online (Sandbox Code Playgroud)

当应用程序启动时,我实例化一个TaskCollection(使用上面列出的第一个Web服务中的数据),将更改事件的侦听器绑定到TaskCollection,并设置一个重复的setTimeout来fetch()TaskCollection实例.

...

TASKS = new TaskCollection();

TASKS.url = ".../employees/" + username + "/tasks"

TASKS.fetch({
  success: function() {
    APP.renderViews();
  }
});


TASKS.bind("change", function() {
  alert("collection changed!");
  APP.renderViews();
});


// Poll every 5 seconds to keep the models up-to-date.
setInterval(function() {
  TASKS.fetch();  
}, 5000);

...
Run Code Online (Sandbox Code Playgroud)

一切都是第一次按照预期呈现.但是在这一点上,如果我使用第二个Web服务更改子任务的状态,我会期望(或两者)Collection更改事件或模型更改事件被触发,但这不会发生.

有趣的是,如果我添加了一个额外的嵌套级别,并且Web服务返回单个模型,我确实得到了更改事件,例如:

"employee":"pkaushik", "tasks":[{"id":45002,"subtasks":[{"id":1.....
Run Code Online (Sandbox Code Playgroud)

但这似乎很糟糕......而且我担心我没有正确构建我的应用程序.如果它有帮助,我会包含更多代码,但这个问题已经相当冗长了.

思考?

Jul*_*ien 8

您正在侦听任务中的事件,而不是子任务.如果您希望任务也为子任务承载事件,则应在Task.initialize中执行以下操作:

var self = this;    
this.subtasks.bind("refresh", function(){ self.trigger("refresh:subtask")});
this.subtasks.each(function(st){ 
  st.bind("change", function(){ self.trigger("change:subtask:" + st.id, st) });
});
Run Code Online (Sandbox Code Playgroud)

您可能还想在刷新事件后刷新绑定.这样,当子任务模型上发生更改事件时,任务模型也将触发更改模型.

Backbone仅在获取后发送刷新事件,您将不会被告知特定模型的更改.查看集合的fetch函数:

options.success = function(resp) {
  collection[options.add ? 'add' : 'refresh'](collection.parse(resp), options);
  if (success) success(collection, resp);
};
Run Code Online (Sandbox Code Playgroud)

默认情况下会调用refresh.这是刷新功能:

refresh : function(models, options) {
  models  || (models = []);
  options || (options = {});
  this.each(this._removeReference);
  this._reset();
  this.add(models, {silent: true});
  if (!options.silent) this.trigger('refresh', this, options);
  return this;
}
Run Code Online (Sandbox Code Playgroud)

它将以静默方式将所有模型添加到集合中(无事件),然后触发刷新事件,但不会识别已更改的元素.