Backbone.js:如何只处理单个视图的选择?

时间:2012-03-10 13:18:16

标签: javascript backbone.js

我坚持以下问题:

我有一个带有属性的模型,该属性定义它是否被明显选择,为了这个问题,我将调用SelectModel。

SelectModel = Backbone.Model.extend({
defaults:{
 isSelected: false
}
})

现在,我真正得到的第一部分是我应该如何处理选择。 如果我想使用观察者模式,我的视图应该监听isSelected属性的更改。但我的观点也首先触发了这一点,所以我会这样做。

SelectView = Backbone.View.extend({
initialize: function(){
this.model.bind("change:isSelected", this.toggleSelectionVisually)
},

events: {
"click" : toggleSelection
},

toggleSelection: function(){
this.model.set({"isSelected": !this.model.get("isSelected");
},

toggleSelectionVisually:(){
//some code that shows that the view is now selected
},
})

所以这本身已经感觉有点荒谬,但我想我只是理解错误。

但是,如果不使我的代码变得非常糟糕,我真正无法实现的部分是处理多个模型的选择,一次只选择一个模型。

SelectListView = Backbone.View.extend({
initialize: function(){
this.collection = new SelectList();
},

toggleSelection: function(){
????
}   
})

那么谁应该通知谁选择更改?哪个部分应该触发它,哪个部分应该听?我真的被困在这一个。对于单个视图来说,这是可行的,因为我很遗憾地丢失了一个集合。

4 个答案:

答案 0 :(得分:3)

在我看到你问题的第二部分之前,我会为你的SelectView建议以下简化:

SelectView = Backbone.View.extend({
  events: {
    "click" : toggleSelection
  },

  toggleSelection: function(){
    this.model.set({"isSelected": !this.model.get("isSelected");
    //some code that shows whether the view is selected or not
  }
});

但是,由于isSelected属性显然是互斥的,因此可以在切换另一个属性时隐式切换,我认为你拥有它的方式最适合你的情况。

因此,使用现有的SelectView,您可以拥有SelectListView,如下所示。 警告:每次选择一个模型时,它会遍历整个模型集合。如果你有大量的模型,这将无法很好地扩展,你将需要缓存先前选择的模型,而不是迭代整个集合。

SelectListView = Backbone.View.extend({
  initialize: function(){
    this.collection = new SelectList();
    this.collection.bind('change:isSelected', this.toggleSelection, this);
  },

  toggleSelection: function(toggledModel){
    //A model was toggled (on or off)
    if(toggledModel.get('isSelected') {
      //A model was toggled ON, so check if a different model is already selected
      var otherSelectedModel = this.collection.find(function(model) {
        return toggledModel !== model && model.get('isSelected');
      });

      if(otherSelectedModel != null) {
        //Another model was selected, so toggle it to off
        otherSelectedModel.set({'isSelected': false});
      }
    }
  }   
});

答案 1 :(得分:3)

我建议你的模型不要跟踪这个,而是视图。

在我看来,模型与其显示无关,而是与您正在跟踪的数据无关。视图应该封装有关数据在何处以及如何显示给用户的所有信息

所以我会将isSelected作为属性放在视图上。然后编写一个切换可见性的方法是微不足道的。如果您需要解释选择特定视图的其他视图,您可以附加一个监听器$(this.el).on('other_visible', toggle_show),您可以使用toggle_visibility

$(this.el).trigger('other_visible')方法上触发该监听器

答案 2 :(得分:2)

非常接近@rrr建议的解决方案,但是将逻辑从View移到Collection,我认为它可以反映到:

SelectsCollection = Backbone.Collection.extend({
  initialize: function() {
    this.on( "change:selected", this.changeSelected );
  },

  changeSelected: function( model, val, opts ){
    if( val ){
      this.each( function( e ){
        if( e != model && e.get( "selected" ) ) e.set( "selected", false );
      });
    };
  },
});

答案 3 :(得分:0)

有不同的方法可以做到这一点。您可以在集合本身上触发事件,并让所有SelectModel实例监听它并相应地更新自己。如果你在集合中有很多SelectModel实例,那似乎有点浪费,因为大多数实例都不会做任何工作。我可能会做的是跟踪视图中的最后一个SelectModel:

SelectListView = Backbone.View.extend({
  initialize: function(){
    this.collection = new SelectList();
    this.lastSelectedModel = null;
  },

  toggleSelection: function(){
    // populate newSelectedModel with the SelectedModel that you're toggling
    var newSelectedModel = getNewSelectedModel();

    if (!newSelectedModel.get('isSelected')) {
      // if the SelectModel isn't already selected, we're about to toggle it On
      // so we need to notify the previously selected SelectModel
      if (this.lastSelectedModel) {
        this.lastSelectedModel.set({isSelected: false});
      }
      this.lastSelectedModel = newSelectedModel;
    } else {
      // if the newSelectedModel we're about to toggle WAS already selected that means
      // nothing is selected now so clear out the lastSelectedModel
      this.lastSelectedModel = null;
    }
    newSelectedModel.set({isSelected: !newSelectedModel.get('isSelected')});
  }   
})