I'm trying to use Backbone.js for the first time and I'm having some trouble. I don't know if my problem is that I'm not understanding how backbone is supposed to work or if it's just a code problem.
I'm trying to create a dynamic menu, and I have no problem creating the main menu bar with it's items, but I can't get the hover event to trigger whenever I hover one of the menu items.
Views
var MenuView = Backbone.View.extend({
initialize: function(items) {
this.menu = items;
//Main navigation bar
this.el = $("#main-nav");
this.trigger('start');
this.render();
},
render: function() {
var me = this;
_.each(this.menu, function(mi) {
mi.render(me.el);
});
return this;
},
handleHover: function(e) {
console.debug(e);
}
});
var MenuItemView = Backbone.View.extend({
tagName: 'li',
className:'menu-item',
events: { //none of these work
'hover a':'handleHover',
'mouseover a':'handleHover',
'mouseover':'handleHover',
'click': 'handleHover',
'click a': 'handleHover'
},
initialize: function(mi) {
this.menuItem = mi;
this.el = $("<li class=\"menu-item\"></li>")
},
render: function(parent) {
this.el.append('<a href="' + this.menuItem.get("link") + '">' + this.menuItem.get("text") + '</a>');
parent.append(this.el);
return this;
},
handleHover: function(ev) {
console.debug("Hovering! " + ev + this.menuItem.get("cid"));
console.debug(ev);
return false;
}
});
Model
var MenuItem = Backbone.Model.extend({
defaults: {
parent: null,
children: [],
link: "",
text: ""
}
});
Startup code
$(document).ready(function() {
var menu = new MenuView([
new MenuItemView( new MenuItem({link: "/", text: "Home"})),
new MenuItemView( new MenuItem({link: "/", text: "Users"})),
new MenuItemView( new MenuItem({link: "/", text: "Configuration"}))
]);
});
Any help will be appreciated!
Thanks!
Update
Ok, after taking the definition of el
outside of the initialize
method on the MenuItemView view, it works, BUT that same element gets reused on all instances of the view, so I had to change the view to the following code in order to make it work the way I want it:
var MenuItemView = Backbone.View.extend({
events: { //none of these work
'hover a':'handleHover',
'mouseover a':'handleHover',
'mouseover':'handleHover',
'click': 'handleHover',
'click a': 'handleHover'
},
el: $('<li class="menu-item"></li>'),
initialize: function(mi) {
this.menuItem = mi;
this.el = $(this.el).clone(true);
},
render: function(parent) {
this.el.append('<a href="' + this.menuItem.get("link") + '">' + this.menuItem.get("text") + '</a>');
parent.append(this.el);
return this;
},
handleHover: function(ev) {
console.debug("Hovering! " + ev + this.menuItem.get("cid"));
console.debug(ev);
return false;
}
});
Wny do I have to clone the element on a new instance?
I'm trying to use Backbone.js for the first time and I'm having some trouble. I don't know if my problem is that I'm not understanding how backbone is supposed to work or if it's just a code problem.
I'm trying to create a dynamic menu, and I have no problem creating the main menu bar with it's items, but I can't get the hover event to trigger whenever I hover one of the menu items.
Views
var MenuView = Backbone.View.extend({
initialize: function(items) {
this.menu = items;
//Main navigation bar
this.el = $("#main-nav");
this.trigger('start');
this.render();
},
render: function() {
var me = this;
_.each(this.menu, function(mi) {
mi.render(me.el);
});
return this;
},
handleHover: function(e) {
console.debug(e);
}
});
var MenuItemView = Backbone.View.extend({
tagName: 'li',
className:'menu-item',
events: { //none of these work
'hover a':'handleHover',
'mouseover a':'handleHover',
'mouseover':'handleHover',
'click': 'handleHover',
'click a': 'handleHover'
},
initialize: function(mi) {
this.menuItem = mi;
this.el = $("<li class=\"menu-item\"></li>")
},
render: function(parent) {
this.el.append('<a href="' + this.menuItem.get("link") + '">' + this.menuItem.get("text") + '</a>');
parent.append(this.el);
return this;
},
handleHover: function(ev) {
console.debug("Hovering! " + ev + this.menuItem.get("cid"));
console.debug(ev);
return false;
}
});
Model
var MenuItem = Backbone.Model.extend({
defaults: {
parent: null,
children: [],
link: "",
text: ""
}
});
Startup code
$(document).ready(function() {
var menu = new MenuView([
new MenuItemView( new MenuItem({link: "/", text: "Home"})),
new MenuItemView( new MenuItem({link: "/", text: "Users"})),
new MenuItemView( new MenuItem({link: "/", text: "Configuration"}))
]);
});
Any help will be appreciated!
Thanks!
Update
Ok, after taking the definition of el
outside of the initialize
method on the MenuItemView view, it works, BUT that same element gets reused on all instances of the view, so I had to change the view to the following code in order to make it work the way I want it:
var MenuItemView = Backbone.View.extend({
events: { //none of these work
'hover a':'handleHover',
'mouseover a':'handleHover',
'mouseover':'handleHover',
'click': 'handleHover',
'click a': 'handleHover'
},
el: $('<li class="menu-item"></li>'),
initialize: function(mi) {
this.menuItem = mi;
this.el = $(this.el).clone(true);
},
render: function(parent) {
this.el.append('<a href="' + this.menuItem.get("link") + '">' + this.menuItem.get("text") + '</a>');
parent.append(this.el);
return this;
},
handleHover: function(ev) {
console.debug("Hovering! " + ev + this.menuItem.get("cid"));
console.debug(ev);
return false;
}
});
Wny do I have to clone the element on a new instance?
Share Improve this question edited Jan 19, 2012 at 19:40 mu is too short 435k71 gold badges858 silver badges818 bronze badges asked Jan 19, 2012 at 13:32 DeletemanDeleteman 8,6907 gold badges27 silver badges40 bronze badges 2 |3 Answers
Reset to default 10hover is not a normal event, but a 'convenience' event provided by jquery. It is a combination of mouseenter and mouseleave.
Binding to mouseenter and mouseleave instead of hover will do what you need.
Re: "Why do I have to clone the element on a new instance?"
The underlying problem is right here:
var MenuItemView = Backbone.View.extend({
// ...
el: $('<li class="menu-item"></li>'),
The $('<li class="menu-item"></li>')
call is executed when MenuItemView
is being defined so you end up with only one $('<li>')
being shared across all instances of MenuItemView
.
If you create the el
inside initialize
or render
then you'll have to bind the events by hand using delegateEvents
:
By default,
delegateEvents
is called within the View's constructor for you [...]
So if you create this.el
yourself then you'll have to call this.delegateEvents()
yourself. For example:
var MenuItemView = Backbone.View.extend({
// ...
render: function() {
this.el = $('<li class="menu-item"><a>' + this.cid + '</a></li>');
this.delegateEvents();
return this;
},
//...
});
Demo: http://jsfiddle.net/ambiguous/RPqMh/2/
However, if you clone
your this.el
with the withDataAndEvents
flag on, then you should be fine:
var MenuItemView = Backbone.View.extend({
el: $('<li class="menu-item"></li>'),
// ...
initialize: function() {
this.el = this.el.clone(true);
this.el.append('<a>' + this.cid + '</a>');
},
//...
});
Demo: http://jsfiddle.net/ambiguous/hCW3F/1/
But if you just this.el.clone()
, it won't work because the delegate
won't be bound to the clone:
var MenuItemView = Backbone.View.extend({
el: $('<li class="menu-item"></li>'),
// ...
initialize: function() {
this.el = this.el.clone();
this.el.append('<a>' + this.cid + '</a>');
},
// ...
});
Demo: http://jsfiddle.net/ambiguous/KZNPA/
But if you add your own delegateEvents
call, you'll be okay:
var MenuItemView = Backbone.View.extend({
el: $('<li class="menu-item"></li>'),
// ...
initialize: function() {
this.el = this.el.clone();
this.el.append('<a>' + this.cid + '</a>');
},
render: function() {
this.delegateEvents();
return this;
},
// ...
});
Demo: http://jsfiddle.net/ambiguous/KZNPA/1/
It seems to me that you don't need this properties:
tagName: 'li',
className:'menu-item'
in MenuItemView if you specify this.el = $('<li class="menu-item"></li>')
;
el
? Consider when$('<li class="menu-item"></li>')
is evaluated and you'll have your answer. – mu is too short Commented Jan 19, 2012 at 19:04el
on theinitialize
method, then the events are not triggered, how can I solve that? – Deleteman Commented Jan 19, 2012 at 19:06