Collections Backbone Collection.fetch()返回第一项null
我在视图中使用以下代码从服务器获取我的收藏:Collections Backbone Collection.fetch()返回第一项null,collections,backbone.js,Collections,Backbone.js,我在视图中使用以下代码从服务器获取我的收藏: initialize: function () { _this = this; this.collection.fetch({ success : function(collection, response) { _.each(response, function(i){ var todo = new TodosMode
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一样。我是主干网新手,希望我只是错过了一些简单的东西。下面是我对您的代码的一个快速浏览。我没有测试过任何东西,所以可能会有打字错误。我仍然不确定这个零散的空模型是从哪里来的,但是如果你按照下面概述的方式重新构造你的应用程序,我怀疑这个问题会消失 模型和系列看起来不错,让我们看看您的视图
el: $('#todos'),
listBlock: $('#todos-list'),
newTodoField: $('#add input'),
//...
template: $('#todo-template').html(),
//...
events: { /* ... */ },
这些应该可以,但您需要确保在加载视图“类”时,所有这些元素都在DOM中。通常,您只需编译一次模板:
template: _.template($('#todo-template').html()),
然后使用this.template
作为获取HTML的函数。我将假定template
是下面的编译模板函数
initialize: function () {
_this = this;
这里有一个意外的全局变量,这可能会导致有趣的bug。你想说var\u this=this代码>
this.el = $(this.el);
主干已经在中为您提供了一个jQuery版本的el
,因此您不需要这样做,只需使用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);
});
},
//...
集合的将在调用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: 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
绑定到集合的“添加”
事件
这样的事情很典型:
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
方法来为您提供数据的简化版本,因此您也可以使用它。模型的属性可用,因此您不必使用get
来获取它。您可以(也可能应该)将todo completed
逻辑推送到模板中,只需一点点
<% if(completed) { %>class="completed"<% } %>
您可以将renderOne
绑定到集合的“add”
事件,以处理新模型的渲染。然后使用回调完成它:
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);
}
});
同样,在保存
上执行错误
回调可能很好
completeTodo: function (e) {
//...
todo.save({
completed: todoCompleted
});
}
此处的save
调用将触发'change:completed'
事件,以便您可以绑定到该事件以调整HTML
removeTodo: function (e) {
//...
}
该调用将在模型上触发一个“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())
即可,
你必须点击一点来打开里面的东西
但这样你就不会错过任何东西
集合的所有事件绑定都将在
视图的初始化方法。如果要删除视图,则
您可能希望覆盖以从集合中解除绑定
要防止内存泄漏,请执行以下操作:
remove: function() {
// Call this.collection.off(...) to undo all the bindings from
// `initialize`.
//...
// Then do what the default `remove` does.
this.$el.remove()
}
您也可以为每个TODO项目使用单独的视图,但对于一些简单的项目来说,这可能过于复杂了。如果您\uuu0(响应).each(函数(o){console.log(o)})代码>?您的每一个
都可能在响应
中拾取了您不期望的内容。我想知道,但我得到的是:这是完整的代码:我更新了我的模型上的默认值
,以包括'content':'something'
,现在集合中的第一项是ID:null | content:something | COMPLETED:false
。我如何阻止它添加默认值作为集合的成员?你的应用程序在很多方面都很奇怪。例如,集合应该在调用success
处理程序之前为您添加模型,这样您就不必手动完成。如果你愿意,我可以在几个小时内给你一个完整的评论;我怀疑解决这个奇怪的问题会让问题消失。非常感谢你花时间来解决这个问题。我已经开始阅读代码并试图理解它。我在下划线上遇到了一个错误,因为id没有定义
,我一辈子都找不到它的来源:好的,我想出来了-renderOne下的模板设置是错误的,应该是this.template(todo.toJSON())
。现在,它似乎只获取模型默认值(请参阅“打印到控制台”集合),而不呈现新项目。对于评论流,我很抱歉,很高兴终于理解了这一点。我已经完成了大部分工作,唯一无法完成的事情是当你添加一个新项目时——它会添加到集合中,但不会添加到DOM中。我在什么地方错过了一个听众吗?不用担心这些评论,我只需要出去一下。下划线模板中的JavaScript错误可能是一个真正需要解决的问题,众所周知的黑光在黑色背景上亮起黑色
remove: function() {
// Call this.collection.off(...) to undo all the bindings from
// `initialize`.
//...
// Then do what the default `remove` does.
this.$el.remove()
}