我正在构建一个小应用程序,用于添加和删除来自ul的li使用Backbonejs.One的SO成员cymen帮我编码它,使用我定制代码一点点。目前如果我添加一个元素并删除,它的工作原理,但第二次我添加一个元素(到ul)并去删除它,我得到
未捕获的TypeError:无法调用未定义的方法'remove'
在此处粘贴我的代码,
HTML:
<input type="text" id="name">
<button id="add">Add</button>
<ul id="mylist"></ul>
JS:
$(function(){
var myCollection = Backbone.Collection.extend();
var myView = Backbone.View.extend({
el:$('body'),
tagName:'li',
initialize : function(e){
this.collection.bind("add",this.render,this);
this.collection.bind("remove",this.render,this);
},
events:{
'click #add' : 'addfoo'
},
addfoo : function(){
var myname= $('#name').val();
$('#name').val('');
this.collection.add({name:myname});
},
render : function(){
$('#mylist').empty();
this.collection.each(function(model){
console.log("myView");
var remove = new myRemoveView({model:model});
remove.render();
});
}
});
var myRemoveView = Backbone.View.extend({
el:$('body'),
events:{
'click .button':'removeFoo'
},
removeFoo : function(){
console.log("here");
this.model.collection.remove(this.model);
},
render : function(){
console.log("second view");
$('#mylist').append('<li>'+this.model.get('name') + "<button class='button'>"+"delete"+"</button></li>");
return;
}
});
var view = new myView({collection: new myCollection()});
});
我不理解的两件事:
i)在removeFoo函数中,我们写
this.model.collection.remove(this.model)
不应该是this.collection.model.remove,那种东西吗?
ii)我添加一个li到ul,然后我删除它,当我添加另一个li(附加到ul工作完美)但这次当我去删除它抛出我上面的错误:未捕获TypeError:无法调用方法'删除'未定义
你可以帮我解决一下我的代码中的这两个疑问吗,顺便说一句SO成员的cymen代码就像一个魅力只有我的定制代码(上图)给我错误。
SO成员cymen的代码:JS Fiddle for his code
谢谢
答案 0 :(得分:2)
首先,您的myRemoveView
正在使用<body>
作为其el
:
var myRemoveView = Backbone.View.extend({
el:$('body'),
这意味着每次点击删除按钮,您都会在每个removeView
上触发myRemoveView
。这肯定不是你想要发生的事情,也不是cymen使用tagName: 'li'
的部分原因。视图有两个通用规则及其el
:
el
一个视图,每个视图一个el
。由于事件处理问题,您不希望视图共享相同的el
;加倍,所以你不希望同一个视图的多个实例共享一个el
。el
应该是视图所关注的DOM的一部分,不多也不少。这使得清理变得非常简单,只需删除与您的视图关联的DOM元素,并且大多数事情都会消失(特别是DOM事件);对于非DOM事件,我们在视图上有remove
方法。另一方面,你的观点不应该(通常)在它自己的el
之外搞乱DOM。这看起来很奇怪:
render : function(){
$('#mylist').append(...);
return;
}
调用者应该负责确定el
的去向,你的观点应该只涉及其中发生的事情,其他一些观点应该对#mylist
负责。此外,render
方法通常会返回this
,以便您可以执行此操作:
$(x).append(some_view.render().el);
将它们放入DOM中。
在视图中指定tagName
和el
:
var myView = Backbone.View.extend({
el: $('body'),
tagName: 'li',
毫无意义,tagName
将被忽略,el
将被使用。
你也在你的小提琴中使用Backbone 0.5.3。您应该尽可能使用最新版本。
如果我们纠正上述情况,那么一切都会开始(再次):
var myView = Backbone.View.extend({
//...
render: function() {
$('#mylist').empty();
this.collection.each(function(model) {
var remove = new myRemoveView({
model: model
});
$('#mylist').append(remove.render().el);
});
}
//...
});
和
var myRemoveView = Backbone.View.extend({
tagName: 'li',
//...
render: function() {
this.$el.text(this.model.get('name'));
this.$el.append("<button class='button'>delete</button>");
return this;
}
});
演示:http://jsfiddle.net/ambiguous/2z4SA/1/
那么您的原始版本会发生什么样的疯狂?关键是el: $('body')
中的myRemoveView
。首先,我们将向myRemoveView
添加一点记录方法,以便更容易地观察发生的情况:
_log: function(method) {
console.log(
method,
': model =', this.model.cid,
' got-collection =', this.model.collection ? 'yes' : 'no',
' view =', this.cid
);
}
请注意,cid
是Backbone创建的内部唯一ID,它只是跟踪事物的便捷方式。然后我们会在this._log
和removeFoo
中致电render
:
removeFoo: function() {
this._log('removeFoo');
if(this.model.collection)
this.model.collection.remove(this.model);
},
render: function() {
this._log('render');
$('#mylist').append('<li>' + this.model.get('name') + "<button class='button'>" + "delete" + "</button></li>");
return;
}
这是一个简单的过程,可以向您显示出现的一切:
您可以点击这里:http://jsfiddle.net/ambiguous/yLYNL/
首先我们将添加 a ,然后在控制台中弹出:
render : model = c1 got-collection = yes view = view2
然后我们添加 b 并看到:
render : model = c1 got-collection = yes view = view4
render : model = c3 got-collection = yes view = view5
您的myView
渲染会重新绘制整个集合,因此我们会看到c1
代表 a ,c3
代表新 b 。到目前为止,一切都很有意义。
现在,当我们尝试删除 a ;首先,我们在 a :
上看到我们removeFoo
removeFoo : model = c1 got-collection = yes view = view2
这会触发一个myView#render
重绘整个集合。此时整个集合只是 b ,所以我们再次看到c3
渲染,一切仍然有意义:
render : model = c3 got-collection = yes view = view6
但现在我们看到一切都在横向发展:
removeFoo : model = c1 got-collection = no view = view4
removeFoo : model = c3 got-collection = yes view = view5
您会看到c3
出现,因为您有两个myRemoveView
个实例(一个用于一个,一个用于 b )绑定到相同el
,因此他们都会看到click .delete
事件,恰好c1
首先看到它。
但c1
在那里做什么呢?那是没有集合的那个,就是那个触发原始错误的集合。您永远不会将myRemoveView
与<body>
上的活动分开,因此您拥有一个僵尸:即使<li>
消失,视图仍然会通过视图{<body>
绑定到c1
{3}}致电。所以你有一个僵尸视图,引用僵尸模型,僵尸僵尸无处不在,你把你的僵尸格斗工具包放在车里。但为什么this.model.collection.remove(this.model)
没有收藏?好吧,你做了:
c1
在collection
上将其从集合中删除;从集合中删除模型会删除模型的{{1}},因为模型不再存在于集合中。