Backbone.js: доступ к конкретному элементу при нажатии
Нуб тут учится backbone.js. Я пытался создать простое горизонтальное меню (каждый пункт меню - это модель, а все меню - это коллекция). Я хотел бы знать, какой пункт меню был нажат. В menuItemView я связываю событие "click a" с функцией "clicked", но оно не срабатывает при нажатии. Самое близкое решение, которое я нашел, было по адресу: http://lostechies.com/derickbailey/2011/10/11/backbone-js-getting-the-model-for-a-clicked-element/ и я попытался воспроизвести подобное функциональность... хотя я думаю, что я скопировал его почти так же, я все еще не могу заставить его работать. Я просмотрел все посты, которые, кажется, касались проблемы определения, на какую модель / элемент нажали, но ни одна из них, похоже, не помогла. Любая помощь будет оценена. Я знаю, что интерактивное меню и получение его идентификатора, вероятно, намного проще в простом jquery, но я подумал, что воспользуюсь этим в качестве примера для изучения магистрали.
HTML
<header>
<ul id="nav">
</ul>
</header>
JAVASCRIPT
(function($) {
window.app = window.app || {};
//Goal:if selected=true, menu item should be highlighted
MenuItem = Backbone.Model.extend({
label: "Default Label",
selected: false,
id: 0
});
MenuList = Backbone.Collection.extend({
model: MenuItem,
initialize: function(models, options) {
//nothing ... yet
}
});
//View for a single item. Returns el that looks like:
// <li id='4' class='false'><a href='#4'> Item 4 </a> </li?
MenuItemView = Backbone.View.extend({
tagName: "li",
render: function() {
var id = this.model.get("id");
var cls = this.model.get("selected");
var lbl = this.model.get("label");
$(this.el).attr('id', id).addClass(cls.toString());
$(this.el).html("<a href=#" + id + " >" + lbl + "</a> </li>");
return this; //recommended as this enables calls to be chained.
},
events: {
"click a": "clicked" //Firebug shows 'a' element bound to
//native 'click' and not 'clicked'. WHY?
},
clicked: function(ev){
alert($(ev.target).text()); //NOT HAPPENING :-(
//do something to highlight menu item via css stuff.
}
});
MenuListView = Backbone.View.extend({
el: $("header > ul"),
initialize: function() {
this.menulist = new MenuList(null, { view: this });
_.bindAll(this, "renderItem");
},
renderItem: function(model) {
var menuitemView = new MenuItemView({ model: model });
menuitemView.render();
$(this.el).append(menuitemView.el);
},
render: function() {
this.collection.each(this.renderItem);
},
setActivePage: function(ev) {
alert($(ev.target).text());
window.app.footerview.updatePageNumber(10);
}
});
var items = new MenuList([
{id: 1, label: "item 1", selected: true},
{id: 2,label: "item 2",selected: false},
{id: 3,label: "item 3",selected: false},
{id: 4,label: "item 4",selected: false}
]);
window.app.menuview = new MenuListView({ collection: items });
window.app.menuview.render();
$("header").html(window.app.menuview.el);
})(jQuery);
Работающий пример этого можно увидеть на jsfiddle: см. Http://jsfiddle.net/gopal_a/4uzcb/3/
1 ответ
Ваша проблема прямо здесь:
$("header").html(window.app.menuview.el);
Ваш window.app.menuview.el
уже в DOM, так как вы определили это так:
el: $("header > ul")
Когда ты $('header').html(...)
вы очищаете то, что уже в <header>
а затем заменить его своим el
; но твой .html()
call уничтожает делегаты событий, которые устанавливает Backbone для обработки событий в представлениях. В результате вы получаете правильный HTML-код в DOM, но к ним не привязана обработка событий.
Оставь свой $("header").html(window.app.menuview.el)
и все начнет работать.
Как в стороне, вам не нужно говорить $(this.el)
, Магистральные представления уже есть this.$el
определены, так что вы можете использовать this.$el
вместо.