I have a tree of categories and I would like to do rending using by Backbone.js instead of using jQuery or do rendering on the server-side. I have the following breakout that I described as template:
<li>
<select class="categories">
<option value="">Select</option>
</select>
<input class="edit" type="button" value="Edit">
<input class="add" type="button" value="Add">
</li>
The tag select I render separately as inner view. When I change select I need get nested categories from the server and append them to the tag li using the template above wrapped in the tag ul. In outer view I create inner view and listen events on click at editing and adding. I have a trouble with the last events when the level of nesting is more than one because they are fires equal times to the level of nesting. What am I doing wrong?
The below code snippet shows how I work with outer and inner views:
var CategoriesInnerView = Backbone.View.extend({
tagName: 'select',
initialize: function(){
_.bindAll(this,'addOne','addAll');
this.collection.bind('reset',this.addAll);
},
addOne: function(category){
this.$el.append(new CategoryView({model:category}).render().el);
},
addAll: function(){
this.collection.each(this.addOne);
},
events: {
'change':'changeSelected'
},
changeSelected:function(){
var children = new Categories();
children.url = 'categories/' + this.$el.val();
var childrenView = new CategoriesOuterView({collection:children});
this.$el.parent().find('ul').remove();
this.$el.parent().append(childrenView.render().el);
children.fetch();
}
});
var CategoriesOuterView = Backbone.View.extend({
tagName: 'ul',
template: _.template($('#categories-template').html()),
initialize:function(){
this.inner = new CategoriesInnerView({collection:this.collection});
},
render: function(){
this.$el.html(this.template);
this.inner.setElement(this.$('select')).render();
return this;
},
events: {
'click .edit':'edit',
'click .add': 'add'
},
edit: function(){
this.renderForm(this.collection.get(this.inner.$el.val()));
},
add: function(){
this.renderForm(new Category());
},
renderForm:function(category){
// some code to render the form
}
});
When you set up nested views, you have to take into account the fact that events will bubble up the DOM tree and that Backbone handles DOM events at the view.el level. This means that in your scenario, nested nodes will also trigger events in the parent nodes if you let the event go up the hierarchy.
See http://jsfiddle.net/PX2PL/ for a demo
A simple solution would be to stop the event propagation in your callbacks
And an updated demo http://jsfiddle.net/PX2PL/1/