In my backbone application, I have a model that looks a little like this,
{
"id" : 145,
"name" : "Group Number 1",
"information" : "Some kind of blurb about group number 1",
"members" : {[
"id" : 1,
"first_name" : "John",
"last_name" : "Doe",
"email" : "[email protected]"
]}
}
Now if I run this.model.get('members').add(newUser)
a new user gets added to the members collection within my model - however it does not fire a change event, why is this? Buy yet if I change the name of the model, then a change event is fired?
All this is done with a view that looks like this,
Individual model view
Views.OrganisationView = Backbone.View.extend({
tagName: 'div',
className:'group group--panel col-sm-3',
template : _.template( $('#tpl-single-group').html() ),
events: {
"click a[data-type=organisation], button[data-type=organisation]" : "edit",
"click .js-delete-group" : "removeOrganisation",
},
initialize: function() {
this.model.on("error", function(model, xhr, options){
console.log(model, xhr, options);
console.log(this);
});
this.listenTo(this.model, 'change', this.render);
this.listenTo(this.model, 'destroy', this.removeView);
},
render: function() {
this.$el.html( this.template({
group: this.model.toJSON()
}));
return this;
},
removeView: function() {
this.remove();
},
removeOrganisation: function(e) {
this.model.destory();
this.remove();
},
edit: function(e) {
e.preventDefault();
Routes.Application.navigate('/organisation/edit/' + this.model.get('id'), { trigger: false } );
var editClient = new Views.OrganisastionEditView({
model: this.model
});
}
});
The second confusing thing that a request event gets thrown, (makes sense seen as though I am saving the model, but an error event gets thrown as well, but there are no errors the xhr
and I am not currently validating the model?
Here is how I am saving the user to members collection in my model,
var member = new Pops.Models.User({ id: element.data('id') });
member.fetch({
success:function() {
self.model.get('members').add(member);
var model = self.model;
self.$('.search').hide();
self.$('button').show();
var projectMember = new Pops.Views.UserInitialsWithAdmin({
model: member
});
self.model.save({validate:false});
self.$('.search').parent().append( projectMember.render().el );
self.$('.search').remove();
}
});
(I'm assuming the first bit of code you've given is just a guideline of what a plain JSON representation of your model would look like, and that
members
is a realCollection
with anadd
method available.)In answer to the first question: change events are only fired when changing a model attribute using
set
. In your case, you're adding to the collection stored in themembers
attribute, but themembers
attribute still contains a reference to the same collection it did before, which means from Backbone's perspective this attribute has not changed. I would suggest attaching listeners directly to themembers
collection. Also see How can I "bubble up" events on nested Backbone collections?.In general nesting models in Backbone is not straightforward, as Jeremy Ashkenas has pointed out. It's often better to keep models flat and store references to related models as arrays of ids, which can then be fetched as necessary.