【问题标题】:Backbone.Collection.reset() => child view is out of sync with parentBackbone.Collection.reset() => 子视图与父视图不同步
【发布时间】:2015-05-04 23:32:53
【问题描述】:

我有一个物品清单。它们存储在骨干可分页集合中。

它们是这样显示的

|---item1---------------|
|---item2---------------|
|---item3---------------|
|---item4---------------|
|---item5---------------|
|---item6---------------|
|---item7---------------|
>

用户可以单击单个项目以在单独的页面中打开详细视图。详细视图已初始化侦听器 当它被创建时。这些侦听器绑定到项目模型。

由于详细视图巨大,我通过切换可见性将其缓存在 DOM 中。 随后单击该项目将切换缓存视图。

------问题来了-----

当项目列表切换到另一个页面时,集合被重置(通过分页器)。并且之前存储在集合中的所有模型都被取消引用并且 创建了一组新模型。所以页面来回切换后,之前打开的item有自己存储的不同副本 在集合中。所以当我在详细视图中(在视图缓存中)更改项目的名称时,项目列表中的名称并没有改变。

视图不同步!因为它们引用了不同的模型。

不确定以前是否有其他人遇到过这种情况。如果你这样做,请与我分享你是如何解决的。

非常感谢。

【问题讨论】:

  • 从 API 文档看来,有三种模式:serverclientinfinite。第一个在内存中只保存一个页面并且每次都重置,但其他两个似乎缓存它。我想知道是不是这个问题?如果没有,您可以查看第 882 行以了解重置发生的条件,并可能为您的应用修改它。
  • @coderek 一些代码来说明您的问题将真正有助于理解您的意思,并为使用提供基础
  • 我将首先查看集合的fullCollection 属性。但是没有一些更具体的代码,很难给你一个好的答案。

标签: backbone.js single-page-application backbone.paginator


【解决方案1】:

在页面更改时,在列表视图项和相应详细视图之间保持新引用的最直接方法是重新呈现详细视图。但我假设此选项在您的项目范围内可接受。

当我的任务是在逻辑上独立的视图中建立关系时,我经常做的是使用侦听器。只要这些视图共享一个唯一标识符(例如,它们都共享一个模型,或者至少具有相同的模型 ID),我总是可以发送一条消息到达我感兴趣的视图。

为此,您需要一个集中的事件中心,使用 Backbone 很容易生成。在一些适当的全局变量(例如,MyApp)中,我们只需这样做:

MyApp.EventBus = _.extend({}, Backbone.Events);

设置详细视图

在详细视图初始化函数中,我会删除此侦听器,

initialize: function () {
  // Listen to a toggle visibility on this view
  this.listenTo(MyApp.EventBus, 'detail-view:toggle-view', toggleView);
},

toggleView: function (id) {
  if (this.model.id == id) {
     // Show this view if I have the passed id
     this.$el.show()
     // Notify the parent list item view that its detail view exists
     MyApp.EventBus.trigger('detail:view:exists', true);
  } else {
    // Hide all other views
    this.$el.hide();
  }
},

changeName: function () {
  // logic that parses DOM user input to 
  // local variable name

  // We now trigger an event 'detail-view:change:name', and we send as 
  // parameters our model's id and the new name
  MyApp.EventBus.trigger('detail-view:change:name', this.model.id, name);
}

设置列表项视图

列表项视图将希望监听名称更改(或您希望列表项知道的详细视图中的任何其他模型属性)。所以我们将为 'detail-view:change:name' 事件设置一个处理程序。

我们还想连接我们的点击处理程序来切换列表项详细视图的可见性。棘手的部分是处理尚未呈现视图的事件(我假设您延迟加载详细视图)。因此,我们为detail:view:exists 事件设置了第二个侦听器,详细视图在捕获detail-view:toggle-view 事件时触发。如果我们没有及时从目标详细视图中听到detail:view:exists 事件(我使用的是 100 毫秒,但您可以根据自己的需要进行调整),然后我们渲染视图。

initialize: function () {
  // Listen to when the detail associated with this list item changes
  // the the list item name
  this.listenTo(MyApp.EventBus, 'detail-view:change:name', onNameChange);
  // Set a property in this view if its detail view exists
  this.listenTo(MyApp.EventBus, 'detail:view:exists', 
    _.bind(function () { this.detailViewExists = true; }, this));
  // Create a debounced function that tests whether this view's
  // detail view exists
  _.debounce(_.bind(this.handleViewState, this), 100);
},

events {
  click: 'toggleDetailView'
},

toggleDetailView: function (id) {
  MyApp.EventBus.trigger('detail-view:toggle-view', this.model.id);
  this.handleViewState();
},

// Debounced function that will wait 100ms asynchronously for the 
// detail view to respond. If the detailViewExists bit is not set to true 
// then we assume the view does not exist and we render it
handleViewState: function () {
  if (!this.detailViewExists) 
     // The view does not exist, render and attach the view

  // Set the bit to false to allow testing in the event that the detail view
  // is destroyed in the future
  this.detailViewExists = false;
},

changeName: function (id, newname) {
  if (this.model.id == id) {
     // Change the name of this list item view
     this.$('.item-name').text(newname);
}

外卖

现在,这两个不同视图之间的引用是共享的唯一标识符。因为,根据设计,这两个标识符在其范围内是唯一的,并且不应更改,并且假设详细视图已被渲染并附加到 DOM,那么无论渲染其状态如何,列表项视图都将始终能够通信及其详细视图。

【讨论】:

  • 这是一个非常简洁的解决方案。权衡是,我们必须为模型视图绑定设置一个单独的事件系统。 (我已经将 Backbone.Radio 用于事件总线,但我从未想过将它放在视图和模型的中间)。由于列表项视图并不复杂,因此不应该有太多的负担。谢谢。
  • 好消息是,您可以通过此解决方案无缝使用 Backbone.Radio(这就是我使用的!)。只需将 EventBus 替换为 `Backbone.Radio.vent`,或者更好地为解决方案创建自己的频道。
  • 顺便说一句,您会注意到它们不是实际的模型视图事件绑定。 将是理想的,并且极大地简化了代码。但是,如果您可以保证在页面更改时集合提供之前使用的相同模型实例,那么视图模型绑定将起作用。我也可以为您提供该解决方案。在上面的答案中,我们只是利用了两个视图共享一个唯一标识符的事实,在本例中为 model.id
  • 我的意思是,从逻辑上讲,我需要一个单独的机制。但可以肯定的是,Backbone.Radio 可以用来实现这一点。
猜你喜欢
  • 2015-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多