Backbone.js Model change events in nested collections not firing as expected
- by Pallavi Kaushik
I'm trying to use backbone.js in my first "real" application and I need some help debugging why certain model change events are not firing as I would expect.
I have a web service at /employees/{username}/tasks which returns a JSON array of task objects, with each task object nesting a JSON array of subtask objects. For example,
[{
"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"}
]
}]
Another web service allows me to change the status of a specific subtask in a specific task, and looks like this: /tasks/45002/subtasks/1/status/red [aside - I intend to change this to a HTTP Post-based service, but the current implementation is easier for debugging]
I have the following classes in my JS app:
Subtask Model and Subtask Collection
var Subtask = Backbone.Model.extend({});
var SubtaskCollection = Backbone.Collection.extend({
model: Subtask
});
Task Model with a nested instance of a Subtask Collection
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
});
Task View to renders the item and listen for change events to the model
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!");
}
});
When the app launches, I instantiate a TaskCollection (using the data from the first web service listed above), bind a listener for change events to the TaskCollection, and set up a recurring setTimeout to fetch() the TaskCollection instance.
...
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);
...
Everything renders as expected the first time. But at this point, I would expect either (or both) a Collection change event or a Model change event to get fired if I change a subtask's status using my second web service, but this does not happen.
Funnily, I did get change events to fire if I added one additional level of nesting, with the web service returning a single object that has the Tasks Collection embedded, for example:
"employee":"pkaushik", "tasks":[{"id":45002,"subtasks":[{"id":1.....
But this seems klugey... and I'm afraid I haven't architected my app right. I'll include more code if it helps, but this question is already rather verbose.
Thoughts?