开发者

Best way to make one model 'selected' in a Backbone.js collection?

I have a collection of models in my Backbone.js application.

It's a list of items that you can hover over with the mouse or navigate around with the keyboard.

If the mouse is hovering, or if the keyboard navigation has the item selected they will both do the same thing: set that particular item/model to be 'selected'.

So in my model, I have an attribute basically called

selected: false

When it's hovered over, or selected with the keyboard, this w开发者_JAVA技巧ill then be

selected: true

But, what is the best way to ensure that when this one model is true, the others are all false?

I'm current doing a basic thing of cycling through each model in the collection and then set the selected model to be true. But I wonder if there is a better, more efficient way of doing this?


Being selected seems a responsibility outside of a model's scope. The notion of selected implies that there are others, but a model can only worry about itself. As such, I'd consider moving this responsibility elsewhere where the notion of many models and having one selected seems more natural and expected.

So consider placing this responsibility either on the collection as an association. So, this.selected would point to the selected model. And then you can add a method to return the selected model in a collection.

Alternatively, you could give this responsibility to the view. You might do this if the selectedness of a model is purely a concern in the View layer.

The by-product of removing the responsibility from the model is that you eliminate the need to cycle through the entire collection when a new model becomes selected.


This is the way I'm doing it. The collection stores a reference to the selected model, but the state is held in the model. This could then be adapted to allow more a more complex algorithm for choosing which models are selected.

JobSummary = Backbone.Model.extend({

  setSelected:function() {
    this.collection.setSelected(this);
  }

});

JobSummaryList = Backbone.Collection.extend({
   model: JobSummary,

   initialize: function() {
     this.selected = null;
   },

   setSelected: function(jobSummary) {
     if (this.selected) {
       this.selected.set({selected:false});
     }
     jobSummary.set({selected:true});
     this.selected = jobSummary;
   }
};


I did something like Mr Eisenhauer suggested. I wanted the concept of paged data as well. Didn't really want to mix in the selected, page number, etc into the collection itself, so I created a "model" for the table data and called it a Snapshot. Something like this:

JobSummary = Backbone.Model.extend({});

JobSummaryList = Backbone.Collection.extend({
   model: JobSummary
};

JobSummarySnapshot = Backbone.Model.Extend({
   defaults: {
     pageNumber: 1,
     totalPages: 1,
     itemsPerPage: 20,
     selectedItems: new JobSummaryList(), // for multiple selections
     jobSummaryList: new JobSummaryList()
   }
});


Check out Backbone.CollectionView, which includes support for selecting models when they are clicked out of the box. The hover case you could implement using the setSelectedModel method.


You might want to have a look at two components of mine:

  • Backbone.Select
  • Backbone.Cycle

Backbone.Select has a minimal surface area. As few methods as possible are added to your objects. The idea is that you should be able to use Backbone.Select mixins pretty much everywhere, with a near-zero risk of conflicts.

Backbone.Cycle is built on top of Backbone.Select. It adds navigation methods and a few more bells and whistles. It probably is the better choice for a greenfield project.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜