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();
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/