I have a page with a toolbar menu at the bottom. I have a function which checks the display property of a block that contains the menu items and sets it to "none" if it's "block" or sets it to "block" if it's "none".
I'm using jQuery to bind the event to the object. I want to use the live() method because I may dynamically add items to this toolbar and I want the event to automatically be attached to new menu elements.
The problem that I'm experiencing is that when I bind the event to the element with live(), the CSS display property of the element I'm checking is always "none". So, the menu never closes.
If I use bind() instead of live(), everything works开发者_开发技巧 like I expect it to.
What's causing this strange behavior with live()?
The demo page reproducing the problem is http://www.ghodmode.com/tbdemo
Thank you.
-- Ghodmode
Because callbacks that are bound using .live() are executed through event delegation, any handlers between the target of .live() and the document will be called. Looking at your code can see that self.hide_menu is bound to the body element. When the event bubbles up from your target that has the class .j_has_menu, the click handler on body (self.hide_menu) is executed causing the menu to close. self.hide_menu does not return false, so the event continuse bubbling up until it reaches the document root and calls the function that you expected self.show_menu. This means that when the menu is open and you click it, self.hide_menu is run first and then self.show_menu is run right after so that the menu is perpetually open.
$(document).ready(function () {
var self = new Toolbar();
$(".j_has_submenu").live("mouseover", self.show_submenu);
$(".j_has_submenu .j_submenu").live("mouseout", self.delay_hide);
$(".j_has_menu").live("click", self.show_menu);
$('.j_toolbar').siblings().add('body').click(self.hide_menu); // <-- the culprit
});
If you're saying that a handler attached via .live()
never fires, this usually happens if you have some other handler between the target of .live()
and the document
that does a return false;
or event.stopPropagation()
.
The reason is that .live()
relies on the event bubbling up to the document in order to invoke the handler. Anything that prevents bubbling, kills .live()
.
<document> <!-- gets a $('p > span').live( 'click', func ) -->
<html>
<body>
<div id="someElem"> <!-- bind click handler that does "return false;" -->
<p>
<span>Hi there!</span> <!-- Intended target of the .live() click
handler won't work because one of
its ancestors has a click with
"return false" -->
</p>
</div>
</body>
</html>
I suggest using delegate
instead of live
and toggle
for showing/hiding the elements.
The advantage of delegate
is that you can specify the root element which handles a group of events (in case of live
the root is always the document
, which can be very inefficent). [Working demo]
$(document).ready(function () {
var self = new Toolbar();
$(".j_toolbar")
.delegate(".j_has_submenu", "mouseover", self.show_submenu)
.delegate(".j_has_submenu .j_submenu", "mouseout", self.delay_hide)
.delegate(".j_has_menu", "click", self.show_menu);
$("body").click(self.hide_menu);
});
Note: You need 1.4.2 for delegate
精彩评论