Reputation: 83
I try to show the same data in two different viewers in the same page by modifying the Todo demo. Any data change will be reflected in both viewers. The code works well with the only one viewer but shows the results that I don't want to want after reloading the page by using fetch. The todolist is shown twice in the first viewer and half of results loose the bond events. Does anyone can help me? Thanks in advance.
The code can be played with the jsfiddle.
HTML:
<div id="todoapp">
<header>
<h1>Todos</h1>
<input class="new-todo" type="text" placeholder="What needs to be done?">
</header>
<section class="main">
<input id=toggle-all class="toggle-all" type="checkbox">
<label for="toggle-all">Mark all as complete</label>
<ul class="todo-list"></ul>
</section>
<footer>
<a class="clear-completed">Clear completed</a>
<div class="todo-count"></div>
</footer>
</div>
<div id="todoapp2">
<header>
<h1>Todos</h1>
<input class="new-todo" type="text" placeholder="What needs to be done?">
</header>
<section class="main">
<input id=toggle-all-2 class="toggle-all" type="checkbox">
<label for="toggle-all-2">Mark all as complete</label>
<ul class="todo-list"></ul>
</section>
<footer>
<a class="clear-completed">Clear completed</a>
<div class="todo-count"></div>
</footer>
</div>
<div id="instructions">
Double-click to edit a todo.
</div>
<!-- Templates -->
<script type="text/template" id="item-template">
<div class="view">
<input class="toggle" type="checkbox" <%= done ? 'checked="checked"' : '' %> />
<label><%- title %></label>
<a class="destroy"> Destroy </a>
</div>
<input class="edit" type="text" value="<%- title %>" />
</script>
<script type="text/template" id="stats-template">
<% if (done) { %>
<a class="clear-completed">Clear <%= done %> completed <%= done == 1 ? 'item' : 'items' %></a>
<% } %>
<div class="todo-count"><b><%= remaining %></b> <%= remaining == 1 ? 'item' : 'items' %> left</div>
</script>
JS:
$(function () {
Todo = Backbone.Model.extend({
defaults: function() {
return {
title: "empty todo...",
order: Todos.nextOrder(),
done: false
};
},
toggle: function() {
this.save({done: !this.get("done")});
}
});
TodoList = Backbone.Collection.extend({
model: Todo,
localStorage: new Backbone.LocalStorage("todos-backbone"),
done: function() {
return this.where({done: true});
},
remaining: function() {
return this.where({done: false});
},
nextOrder: function() {
if (!this.length) return 1;
return this.last().get('order') + 1;
},
comparator: 'order'
});
var Todos = new TodoList;
TodoView = Backbone.View.extend({
tagName: "li",
template: _.template( $('#item-template').html() ),
events: {
"click .toggle" : "toggleDone",
"dblclick .view" : "edit",
"click a.destroy" : "clear",
"keypress .edit" : "updateOnEnter",
"blur .edit" : "close"
},
initialize: function() {
this.listenTo(this.model, 'change', this.render);
this.listenTo(this.model, 'destroy', this.remove);
},
render: function() {
this.$el.html( this.template(this.model.toJSON()) );
this.$el.toggleClass('done', this.model.get('done') );
this.input = this.$('.edit');
//alert(this.input.val() );
return this;
},
toggleDone: function() {
this.model.toggle();
},
edit: function() {
this.$el.addClass("editing");
this.input.focus();
},
close: function() {
var value = this.input.val();
if (!value) {
this.clear();
} else {
this.model.save({title: value});
this.$el.removeClass("editing");
}
},
updateOnEnter: function(e) {
if (e.keyCode == 13) this.close();
},
clear: function() {
this.model.destroy();
}
});
var AppView = Backbone.View.extend({
//el: $("#todoapp"),
statsTemplate: _.template($('#stats-template').html()),
events: {
"keypress .new-todo": "createOnEnter",
"click .clear-completed": "clearCompleted",
"click .toggle-all": "toggleAllComplete"
},
initialize: function() {
this.input = this.$(".new-todo");
this.allCheckbox = this.$(".toggle-all")[0];
this.listenTo(Todos, 'add', this.addOne);
this.listenTo(Todos, 'reset', this.addAll);
this.listenTo(Todos, 'all', this.render);
this.footer = this.$('footer');
this.main = this.$('.main');
//Todos.fetch();
Todos.fetch({reset:true});
},
render: function() {
var done = Todos.done().length;
var remaining = Todos.remaining().length;
if (Todos.length) {
this.main.show();
this.footer.show();
this.footer.html(this.statsTemplate({done: done, remaining: remaining}));
} else {
this.main.hide();
this.footer.hide();
}
this.allCheckbox.checked = !remaining;
},
addOne: function(todo) {
var view = new TodoView({model: todo});
//console.log(view.render().el );
//this.$(".todo-list").append( view.render().el );
this.$(".todo-list").append( view.render().el );
console.log( this.main.parent() );
},
addAll: function() {
Todos.each(this.addOne, this);
},
createOnEnter: function(e) {
if (e.keyCode != 13) return;
if (!this.input.val()) return;
Todos.create({title: this.input.val()});
this.input.val('');
},
clearCompleted: function() {
_.invoke(Todos.done(), 'destroy');
return false;
},
toggleAllComplete: function () {
var done = this.allCheckbox.checked;
Todos.each(function (todo) { todo.save({'done': done}); });
}
});
var app1 = new AppView({ el: $("#todoapp") });
var app2 = new AppView({ el: $("#todoapp2") });
});
Upvotes: 0
Views: 47
Reputation: 5402
The reason is you are using only one collection for the both the Views.
To solve this problem you can fetch the collection only once after both the views are initialized.
Upvotes: 1