Find Backbone.js View if you know the model?

For a page using Backbone.js, for a collection bound to a view ( RowsView , creates <ul> ), which creates routines ( RowView , creates <li> ) for each model in the collection, I have a problem with setting up inline editing for these models in the collection.

I created an edit() method in a RowView that replaces the contents of li text field, and if the user presses tab while in this text field, I would like to call edit() following form in the list.

I can get the model of the following model in the collection:

 // within a RowView 'keydown' event handler var myIndex = this.model.collection.indexOf(this.model); var nextModel = this.model.collection.at(myIndex+1); 

But the question is how to find the representation attached to this model. Parent RowsView View does not retain links to all Views child elements; this is the render() method:

 this.$el.html(''); // Clear this.model.each(function (model) { this.$el.append(new RowView({ model:model} ).render().el); }, this); 

Does it need to be rewritten to keep a separate array of pointers to all the RowView that it has underneath? Or is there a smart way to find the “View” that got the famous model attached to it?

Here's jsFiddle of the whole problem: http://jsfiddle.net/midnightlightning/G4NeJ/

+8
source share
2 answers

It is not very convenient to store a link to a view in your model, however you can associate View with a model with events, do the following:

 // within a RowView 'keydown' event handler var myIndex = this.model.collection.indexOf(this.model); var nextModel = this.model.collection.at(myIndex+1); nextModel.trigger('prepareEdit'); 

In the RowView, listen for the prepareEdit event and in this edit () call, something like this:

 this.model.on('prepareEdit', this.edit); 
+11
source share

I would say that your RowsView should keep track of its RowView s component. An individual RowView indeed part of a RowsView , and it makes sense that the view should track parts of it.

So your RowsView will have a render method like this:

 render: function() { this.child_views = this.collection.map(function(m) { var v = new RowView({ model: m }); this.$el.append(v.render().el); return v; }, this); return this; } 

Then you just need a way to convert Tab to index in this.child_views .


One way is to use events, Backbone views have Backbone.Events mixed, so that views can trigger events on themselves, while others can listen to these events. In your RowView , you might have the following:

 events: { 'keydown input': 'tab_next' }, tab_next: function(e) { if(e.keyCode != 9) return true; this.trigger('tab-next', this); return false; } 

and your RowsView will be v.on('tab-next', this.edit_next); in this.collection.map , and you can have the edit_next sort:

 edit_next: function(v) { var i = this.collection.indexOf(v.model) + 1; if(i >= this.collection.length) i = 0; this.child_views[i].enter_edit_mode(); // This method enables the <input> } 

Demo: http://jsfiddle.net/ambiguous/WeCRW/

An option on this would be to add a link to the RowsView on the RowView , and then tab_next could directly call this.parent_view.edit_next() .


Another option is to place the keydown handler inside the RowsView . This adds some connection between RowView and RowsView , but this is probably not a big problem in this case, but it is a bit uglier than a solution for events:

 var RowsView = Backbone.View.extend({ //... events: { 'keydown input': 'tab_next' }, render: function() { this.child_views = this.collection.map(function(m, i) { var v = new RowView({ model: m }); this.$el.append(v.render().el); v.$el.data('model-index', i); // You could look at the siblings instead... return v; }, this); return this; }, tab_next: function(e) { if(e.keyCode != 9) return true; var i = $(e.target).closest('li').data('model-index') + 1; if(i >= this.collection.length) i = 0; this.child_views[i].enter_edit_mode(); return false; } }); 

Demo: http://jsfiddle.net/ambiguous/ZnxZv/

+2
source share

All Articles