我在视图中使用以下代码从服务器获取我的集合:
initialize: function () {
_this = this;
this.collection.fetch({
success : function(collection, response) {
_.each(response, function(i){
var todo = new TodosModel({
id: i.id,
content: i.content,
completed: i.completed
});
// Add to collection
_this.collection.add(todo);
// Render
_this.render(todo);
});
},
error : function(collection, response) {
console.log('ERROR GETTING COLLECTION!');
}
});
},
这似乎有效 - 这是我服务器的输出:
{
"0": {
"id": 1,
"content": "one",
"completed": false
},
"3": {
"id": 4,
"content": "two",
"completed": true
},
"4": {
"id": 5,
"content": "tester",
"completed": false
}
}
除非我退出我的收藏,否则第一个位置会有一个null
条目:
然后会导致问题,好像我添加了一个项目,它需要最后一个元素的ID。我是骨干的新手,希望我能错过一些简单的东西。
答案 0 :(得分:1)
这是我快速浏览代码的问题。我没有测试任何东西所以可能有拼写错误。我仍然不确定流浪空模型的来源,但如果您按照下面的描述重组您的应用程序,我怀疑问题会消失。
模型和集合看起来没问题,所以让我们看看你的观点。
el: $('#todos'),
listBlock: $('#todos-list'),
newTodoField: $('#add input'),
//...
template: $('#todo-template').html(),
//...
events: { /* ... */ },
这些应该没问题但是你需要确保在加载视图“class”时所有这些元素都在DOM中。通常你会编译一次模板:
template: _.template($('#todo-template').html()),
然后只使用this.template
作为获取HTML的函数。我假设template
是下面的编译模板函数。
initialize: function () {
_this = this;
这里有一个偶然的全局变量,这可能会导致有趣的错误。你想说var _this = this;
。
this.el = $(this.el);
Backbone已经在$el
为您提供了el
的jQuery'd版本,因此您无需执行此操作,只需使用this.$el
。
this.collection.fetch({
success : function(collection, response) {
_.each(response, function(i) {
var todo = new TodosModel({ /* ... */ });
// Add to collection
_this.collection.add(todo);
// Render
_this.render(todo);
});
},
//...
集合的fetch
会在调用success
处理程序之前将模型添加到集合中,因此您不必创建新模型或向集合添加任何内容。通常,render
方法渲染整个事物而不是仅渲染一个部分,并将视图的render
绑定到集合的"reset"
事件; fetch
调用将在获取时触发"reset"
事件,因此通常的模式如下所示:
initialize: function() {
// So we don't have to worry about the context. Do this before you
// use `render` or you'll have reference problems.
_.bindAll(this, 'render');
// Trigger a call to render when the collection has some stuff.
this.collection.on('reset', this.render);
// And go get the stuff we want. You can put your `error` callback in
// here if you want it, wanting it is a good idea.
this.collection.fetch();
}
现在为render
:
render: function (todo) {
var templ = _.template(this.template);
this.listBlock.append(templ({
id: todo.get('id'),
content: todo.get('content'),
completed: todo.get('completed')
}));
// Mark completed
if(todo.get('completed')) {
this.listBlock.children('li[data-id="'+todo.get('id')+'"]')
.addClass('todo-completed');
}
}
通常情况下,这将分为两部分:
render
渲染整个集合。renderOne
,用于呈现单个模型。这也允许您将renderOne
绑定到集合的"add"
事件。这样的事情很典型:
render: function() {
// Clear it out so that we can start with a clean slate. This may or
// may not be what you want depending on the structure of your HTML.
// You might want `this.listBlock.empty()` instead.
this.$el.empty();
// Punt to `renderOne` for each item. You can use the second argument
// to get the right `this` or add `renderOne` to the `_.bindAll` list
// up in `initialize`.
this.collection.each(this.renderOne, this);
},
renderOne: function(todo) {
this.listBlock.append(
this.template({
todo: todo.toJSON()
})
)
// Mark completed
if(todo.get('completed')) {
this.listBlock.find('li[data-id="' + todo.id + '"]')
.addClass('todo-completed');
}
}
请注意使用toJSON
向模板提供数据。 Backbone模型和集合使用toJSON
方法为您提供数据的简化版本,以便您也可以使用它。模型id
可用作属性,因此您无需使用get
即可获取该属性。您可以(也可能应该)将todo-completed
逻辑推入模板,只需一点
<% if(completed) { %>class="completed"<% } %>
在正确的地方应该做到这一点。
addTodo: function (e) {
//...
var todo = new TodosModel({
id: todoID,
content: todoContent,
completed: todoCompleted
});
this.render(todo);
todo.save();
_this.collection.add(todo);
您可以将renderOne
绑定到集合的"add"
事件,以处理渲染新模型的问题。然后使用save
回调来完成它:
var _this = this;
var todo = new TodosModel({ /* ... */ });
todo.save({}, {
wait: true,
success: function(model, response) {
// Let the events deal with rendering...
_this.collection.add(model);
}
});
同样,error
上的save
回调可能会很好。
completeTodo: function (e) {
//...
todo.save({
completed: todoCompleted
});
}
此处save
调用将触发'change:completed'
事件,因此您可以绑定该事件以调整HTML。
removeTodo: function (e) {
//...
}
destroy
来电将触发模型and on the collection上的"destroy"
事件:
在集合中的模型上触发的任何事件也将 为方便起见,直接在集合上触发。这个 允许您监听任何模型中特定属性的更改 在一个集合中,[...]
因此,您可以在集合上侦听"destroy"
个事件,并使用它们从显示中删除TODO。并且破坏模型应该在没有您干预的情况下将其从集合中删除。
printColl: function () {
this.collection.each(function (todo) {
console.log('ID: '+todo.get('id')+' | CONTENT: '+todo.get('content')+' | COMPLETED: '+todo.get('completed'));
});
}
你可以console.log(this.collection.toJSON())
代替,
你必须点击一下才能打开东西
控制台,但你不会错过任何方式。
集合的所有事件绑定都将在您的
查看initialize
方法。如果您要删除视图
你想覆盖remove
取消绑定集合
防止内存泄漏:
remove: function() {
// Call this.collection.off(...) to undo all the bindings from
// `initialize`.
//...
// Then do what the default `remove` does.
this.$el.remove()
}
您也可以为每个TODO项目使用单独的视图,但这对于简单的事情可能过度。