模型主干视图在第一次集合重新渲染时无法从 DOM 中删除

Posted

技术标签:

【中文标题】模型主干视图在第一次集合重新渲染时无法从 DOM 中删除【英文标题】:Model Backbone Views can't be removed from DOM at first Collection re-render 【发布时间】:2013-05-04 11:07:57 【问题描述】:

我一整天都在面对一个问题,我有点绝望!我很确定这对于这里的一些 Backbone 专家来说会很简单......我是 Backbone 的新手,我可能没有采取最好的方法。任何帮助或建议都会很棒!

问题

将新项目添加到集合后,该集合被重新渲染,我可以看到新项目添加到我的 DOM 中。 如果我单击“删除”按钮,则事件被触发,新项目被销毁......但元素保留在 DOM 中。如果我重新渲染页面,(刷新或导航到其他地方并返回)它就消失了。

而如果我添加一个新项目,在我的集合被渲染后立即导航到其他地方,然后返回并按“删除”,这一次它会被销毁并从 DOM 中删除...... 有什么想法吗?

添加新项目

save: function(e)
    e.preventDefault();
    var data = form2js('deviceForm', '.', true);
    //Allow to create or edit a model;
    this.model.set(data);
    this.model = this.collection.create(this.model, 
        wait: true,
        success: function()
            Utils.alert('success', 'Device has been added/edited');
            app.vent.trigger("devices:show");
        
    );

此代码在我添加新项目时显示的视图内。添加新项目时,它会调用下面的函数。 this.collection 是我的设备列表,在路由器内部重复使用。

路由器

showDevices: function()
    if (!this.devices)
        this.devices = new Devices();
        this.devices.fetch();
    
    if (this.devicesList) this.devicesList.remove();
    this.devicesList = new DevicesView(collection: this.devices);
    $('.addPadding').hide().slideDown(1000, 'linear').html(this.devicesList.render().el);
,

我只提取一次列表,然后在每次需要时重复使用它,避免不必要的提取。如果存在,我会清理视图并实例化一个新视图。

收藏(查看)

initialize: function()
    _.bindAll(this, "render", "addOne");

    this.collection.on('add', this.addOne);
    this.collection.on('reset', this.addAll);
,
render: function()
    this.$el.html(this.template);
    this.addAll();
    return this;
,
addOne:function(device)
    var devi = new DeviceView(model: device);
    this.$el.find(".devices-list").append(devi.render().el);
,
addAll: function()
    this.collection.each(this.addOne, this)

我的集合视图中没有定义 el 属性。绑定到集合事件,以便为新项目呈现或获取完成。

项目视图

tagName: 'tr',
events: 
    'click .remDevice': 'removeDevice',
    'click .editDevice' : 'editDevice'
,
template: _.template( template ),
initialize: function()
    this.listenTo(this.model, 'destroy', this.remove);
,
render: function()
    this.$el.html(this.template(this.model.toJSON()));
    return this;
,
removeDevice:function()
    this.model.destroy();

我的项目被附加到表格中,添加到 tbody 元素中。该表位于我的集合视图的模板中。当我单击删除按钮时,模型被销毁并触发事件并调用 this.remove。但是在创建项目后重新呈现集合时不起作用。虽然之后工作......

希望我提供了足够的信息!提前非常感谢! PS:控制台没有错误,我的调试器中填充了模型+集合。

编辑: this.remove 在每次点击时都会被调用,因为我的模型每次都会被破坏。通过覆盖它并尝试手动删除元素:

this.$el.remove();

没有区别,也没有显示任何错误。 this.$el 包含我新添加的元素。

编辑 2 一条新线索:如果我有 6 个设备的集合,添加第 7 个,然后尝试删除其中任何一个,除非我重新渲染,否则它们会被销毁但不会从 DOM 中删除。所以它不仅仅与新项目相关联,而是我向集合中添加了一个新项目,渲染它并尝试删除一个项目。 此外,编辑功能仍然适用于每个项目,并将我重定向到具有正确模型的正确页面进行编辑。

LAST EDIT 我之前尝试清空集合以添加新项目以避免僵尸......但没有改变任何东西。我希望它能避免随机的副作用 在我的收藏视图中

addAll: function()
                this.$el.find(".devices-list").empty();
                this.collection.each(this.addOne, this)
            ,

【问题讨论】:

我还不完全确定为什么,但我不喜欢您收藏视图中的行_.bindAll(this, "render", "addOne"); 那行在做什么?如果你删除它,它会起作用吗? 从您在 Collection 下提供的代码看来,它实际上是一个视图。 @MikeV,那一行相当于做 _this = this,然后在我的其他函数中使用 _this。它只是让我的上下文保持我的观点。感谢您的编辑!对此感到抱歉 如果您将第三个 this 参数添加到您的 collection.on() 行,您将不需要 _.bindAll 的东西。我尽量避免使用_.bindAll 调试您的 ItemView/DeviceView 的一个好方法是添加 this.model.on('all', function(eventName)console.log(eventName)); 然后检查控制台以查看正在触发的事件。你真的只需要弄清楚为什么destroy 事件没有触发remove 函数。一旦你解决了这个问题,我想你会解决你的问题。我删除了我的答案,因为它不是解决方案。 【参考方案1】:

我找到了一种“肮脏”的方法来解决我的问题。 我在“删除函数”中有一个断点。直观地比较 this.$el 和添加到表中的行是完全相同的行。

所以我尝试这样做:

$('.devices-list').find(this.$el)

但没有返回任何内容...这太疯狂了,因为它们包含完全相同的数据!我假设 this.$el 以僵尸版本或其他形式呈现。我很确定这些项目的渲染方式有问题……但我肯定找不到,我愿意接受建议……

解决方案

在我的设备视图/项目视图中,我编辑了这两个函数,将模型id添加到tr,然后使用jquery在DOM中找到它。像这样,我专注于现有元素,而不是缓存 jquery 东西的 $el...

render: function()
        this.$el.html(this.template(this.model.toJSON()));
        this.$el.attr('id', this.model.id);
        return this;
    ,
remove: function()
            var elem =  $('.devices-list').find('#'+this.model.id);
            $(elem).find('#'+this.model.id).slideUp(1000);
            $(elem).find('#'+this.model.id).remove();
        

希望有人会得到一个更好的主意,或者有人会从我的解决方案中得到帮助!

【讨论】:

以上是关于模型主干视图在第一次集合重新渲染时无法从 DOM 中删除的主要内容,如果未能解决你的问题,请参考以下文章

为父级调用渲染的主干子视图

主干更新视图

(重新)在更改事件处理程序中渲染主干视图不起作用

重新初始化主干视图后未触发事件

如何通过主干中的 ajax 调用使用模型渲染多个视图

如何从主干中的另一个视图绑定元素上的事件