Reputation: 425
I've got a template for a todo with a list for comments. Each todo has an array "comments" of comments in localstorage. I fetch all todos, iterate through each todo's "comments" array and I want all comments to be assigned to the corresponding todo. How do I append to the right comment-list?
Currently I get the output like this one:
Post1
Comment1_Post1
Comment2_Post1
Comment1_Post2
Comment2_Post2
Post2
Comment1_Post2
Comment2_Post2
Edit1: the new CommentCollectionView
render: function() {
this.$el.html(this.template());
var commentList = this.$("ul.comment-list");
this.collection.each(function(comment) {
var commentView = new CommentView({model: comment});
commentList.append(commentView.render().el);
});
return this;
},
HTML:
<body>
<div class="content">
<ul class="todos-list"></ul>
</div>
// Templates
<script type="text/template" id="todo-template">
<label class="todo-content"><%= content %></label>
<ul class="comment-list" style="margin-left: 2em"></ul>
</script>
<script type="text/template" id="comment-template">
<label class="comment-content"><%= content %></label>
</script>
Todo View:
var TodoView = Backbone.View.extend({
tagName: "li",
template: _.template($("#todo-template").html()),
events: {
"click button.addComment": "addComment"
},
initialize: function() {
_.bindAll(this, "render");
this.model.bind("change", this.render);
var commentsArray = this.model.get("comments");
var commentCollection = new CommentCollection();
commentCollection.add(commentsArray);
var commentCollectionView = new CommentCollectionView({model: commentCollection});
}
});
Comment Collection View:
var CommentCollectionView = Backbone.View.extend({
initialize: function() {
_.bindAll(this, "render", "appendItem", "addAll", "renderComment");
this.model.bind("reset", this.addAll);
this.model.bind("change", this.render);
this.model.bind("add", this.appendItem);
this.model.trigger("reset");
},
addAll: function() {
this.model.each(this.appendItem);
},
appendItem: function(comment) {
var commentView = new CommentView({model: comment});
$("ul.comment-list").append(commentView.render().el);
}
});
Upvotes: 1
Views: 3288
Reputation: 6552
The problem is in the definition of the TodoModel, you did not pasted the code of it but I could assume the issue, is a common issue with data-types that are objects.
TodoModel has an attribute that you are defining in your default in this way:
var TodoModel = Backbone.Model.extend({
defaults : {
//some
comments : []
}
});
So comments is an array that is always being used in all of your instances of TodoModel. Change your defaults to be in this way:
var TodoModel = Backbone.Model.extend({
defaults : function(){
return {
//some
comments : []
}
}
});
Update, because seems to be an issue with the scope of the selector of jQuery: To be sure that you use only DOM elements of your current view use this. instead of the normal jQuery Call, example: this.$('ul.comment-list')
Upvotes: 2
Reputation: 434965
I think your problem is right here:
appendItem: function(comment) {
var commentView = new CommentView({model: comment});
$("ul.comment-list").append(commentView.render().el);
}
Your $('ul.comment-list')
finds all the <ul class="comment-list">
when you only want the specific <ul>
for that todo item.
You should break your #todo-template
into two pieces:
<script type="text/template" id="todo-template">
<label class="todo-content"><%= content %></label>
</script>
<script type="text/template" id="comments-template">
<ul class="comment-list" style="margin-left: 2em"></ul>
</script>
Then use #comments-template
as the template for CommentCollectionView
:
var CommentCollectionView = Backbone.View.extend({
template: _.template($("#comments-template").html()),
render: function() {
this.$el.html(this.template());
return this;
},
//...
});
var TodoView = Backbone.View.extend({
//...
render: function() {
this.$el.html(this.template(...));
// Use 'collection' here, not 'model'
var c = new CommentCollectionView({collection: commentCollection});
this.$el.append(c.render().el);
return this;
}
});
Then your appendItem
becomes:
appendItem: function(comment) {
var commentView = new CommentView({model: comment});
this.$el.append(commentView.render().el);
}
and that should put the CommentView
into the right <ul>
.
Upvotes: 3