Backbone.js - доступ к модели из события click
У меня есть BoardView, содержащий CellCollection для CellModels. Я беру коллекцию из db, а затем создаю CellViews.
Все это работает плавно, пока я не попытаюсь получить доступ к CellModel через событие click на BoardView. Я вообще не могу добраться до базовых моделей... только взглядов. Есть ли способ сделать это?
Я попытался включить соответствующий код ниже:
CellModel = Backbone.Model.extend({});
CellCollection = Backbone.Collection.extend({
model : CellModel
});
CellView = Backbone.View.extend({
className : 'cell',
});
BoardView = Backbone.View.extend({
this.model.cells = new CellCollection();
render : function() {
this.cellList = this.$('.cells');
return this;
},
allCells : function(cells) {
this.cellList.html('');
this.model.cells.each(this.addCell);
return this;
},
addCell : function(cell) {
var view = new Views.CellView({
model : cell
}).render();
this.cellList.append(view.el);
},
events : {
'click .cell' : 'analyzeCellClick',
},
analyzeCellClick : function(e) {
// ?????????
}
});
Мне нужен щелчок, чтобы "произойти" в BoardView, а не CellView, потому что он включает логику, специфичную для платы.
Ответы
Ответ 1
Я могу придумать хотя бы два подхода, которые вы можете использовать здесь:
-
Передайте BoardView в CellView при инициализации, а затем обработайте событие в CellView:
var CellView = Backbone.View.extend({
className : 'cell',
initialize: function(opts) {
this.parent = opts.parent
},
events : {
'click' : 'analyzeCellClick',
},
analyzeCellClick : function() {
// pass the relevant CellModel to the BoardView
this.parent.analyzeCellClick(this.model);
}
});
var BoardView = Backbone.View.extend({
// ...
addCell : function(cell) {
var view = new Views.CellView({
model : cell,
parent : this
}).render();
this.cellList.append(view.el);
},
analyzeCellClick : function(cell) {
// do something with cell
}
});
Это сработает, но я предпочитаю, чтобы представления не вызывали друг друга, поскольку они делают их более тесно связанными.
-
Прикрепите идентификатор CellModel к DOM при его рендеринге:
var CellView = Backbone.View.extend({
className : 'cell',
render: function() {
$(this.el).data('cellId', this.model.id)
// I assume you're doing other render stuff here as well
}
});
var BoardView = Backbone.View.extend({
// ...
analyzeCellClick : function(evt) {
var cellId = $(evt.target).data('cellId'),
cell = this.model.cells.get(cellId);
// do something with cell
}
});
Это, вероятно, немного чище, потому что он избегает тесной связи, упомянутой выше, но я думаю, что любой из них будет работать.
Ответ 2
Хороший вопрос! Я думаю, лучшим решением было бы реализовать
EventBus aka EventDispatcher
для координации всех событий между различными областями вашего приложения.
Переход на этот маршрут кажется чистым, слабо связанным, легко реализуемым, расширяемым и фактически предложенной базовой документацией, см. Backbone Docs
Пожалуйста, также прочитайте здесь здесь и здесь, потому что (даже хотя я и старался), мое собственное объяснение кажется мне посредственным.
Пятиступенчатое объяснение:
-
Создайте EventBus в своем основном или где-то еще в качестве утилиты и включите/требуйте
var dispatcher = _.clone(Backbone.Events); // or _.extends
-
Добавьте к нему один или несколько hanlder (s) обратных вызовов
dispatcher.CELL_CLICK = 'cellClicked'
-
Добавьте триггер в Eventlistener вашего childView (здесь: CellView)
dispatcher.trigger(dispatcher.CELL_CLICK , this.model);
-
Добавить прослушиватель в функцию Initialize вашего parentView (здесь: BoardView)
eventBus.on(eventBus.CARD_CLICK, this.cardClick);
-
Определите соответствующий обратный вызов внутри вашего родительского элемента (и добавьте его в свой _.bindAll)
cellClicked: function(model) {
// do what you want with your data here
console.log(model.get('someFnOrAttribute')
}
Ответ 3
Я бы позволил CellView
обработать событие click, но он просто вызовет событие Backbone:
var CellView = Backbone.View.extend({
className : 'cell',
initialize: function() {
_.bindAll(this, 'analyzeCellClick');
}
events : {
'click' : 'analyzeCellClick',
},
analyzeCellClick : function() {
this.trigger('cellClicked', this.model);
}
});
var BoardView = Backbone.View.extend({
// ...
addCell : function(cell) {
var view = new Views.CellView({
model : cell
}).render();
this.cellList.append(view.el);
view.bind('cellClicked', function(cell) {
this.analyzeCellClick(cell);
};
},
analyzeCellClick : function(cell) {
// do something with cell
}
});