Given the following jQuery .on() event map:
$('header').on({
mouseenter: function(e) {},
mouseleave: function(e) {},
}, 'li');
How can I share a var $this = $(this) variable between both the mouseenter and mouseleave events to keep it DRY?
EDIT:
To be clearer, if I want to apply the logic to each event in the event map, let's say:
mouseenter: function(e) {
// Grabs the list element.
var $this = $(this);
// Gets the sub-menu of the active menu item, if there is one.
var $subMenu = $this.find('.main-menu__sub-menu').first();
if ($subMenu.length) {
// Do something...
}
},
mouseleave: function(e) {
// Perform the same checks, and get the same variables as above...
},
click: function(e) {
// Again, perform the same checks and grab the same variables as above...
}
I obviously don't want to repeat my logic, but I require getting the li element that's firing the event, which will be the same for all events within the event map... Hopefully that makes more sense?
With your expanded description, you could go for something like this:
function getSubmenu(li) {
// Grabs the list element.
var $li = $(li);
// Gets the sub-menu of the active menu item, if there is one.
var $subMenu = $li.find('.main-menu__sub-menu').first();
return $subMenu;
}
$('header').on({
mouseleave: function(e) {
var $subMenu = getSubmenu(this)
// do some stuff...
},
click: function(e) {
var $subMenu = getSubmenu(this)
// do some other stuff...
}
}, 'li');
Not sure why you would need it since the this variable will reference to the header element on both functions..
but a way you can do it is declaring the variable outside of the scope
var $this;
$('header').on({
mouseenter: function (e) {
$this = $(this);
},
mouseleave: function (e) {
$this; // is available
},
}, 'li');
Related
I'm looking for a way to pass a variable that is relative to the element to both mouseenter and mouseleave events. For example, if I had:
jQuery('.element').on({
mouseenter: function () {
var $child = jQuery(this).find('.child');
$child.fadeIn();
},
mouseleave: function () {
var $child = jQuery(this).find('.child');
$child.fadeOut();
}
});
Is there a way to avoid defining the $child variable twice? I was able to figure this out using .hover(), however I am now unable to use that as I am calling it on dynamically generated elements, for which .hover() will not work.
You can use this way to delegate both events:
jQuery(document).on("mouseenter mouseleave", ".element", function(e){
jQuery(this).find('.child').fadeToggle();
// you can check for e.type for more complex logic
});
The syntax to delegate with different handlers is:
jQuery(document).on({
mouseenter: function () {
//...
},
mouseleave: function () {
//...
}
}, ".element");
Use something like that:
jQuery('.element').on({
mouseenter: function (e) {
var ele = e.currentTarget;
ele.fadeIn();
},
mouseleave: function (e) {
var ele= e.currentTarget;
ele.fadeOut();
}
});
You could reuse the same function in both events, something like:
jQuery('.element').on({
mouseenter: function () {
handleFade("enter", jQuery(this));
},
mouseleave: function () {
handleFade("leave", jQuery(this));
}
});
function handleFade(state, $elem){
var $child = $elem.find('.child');
if(state=="enter"){
$child.fadeIn();
} else if(state=="leave"){
$child.fadeOut();
}
}
I have tried sooooo many different methods of this that others have suggested, but I don't understand what i'm doing wrong and really need some help. I have tried using various combinations of hover, mouseenter/mouseleave, on/off, bind/unbind.
Basically, I can get things to unbind, but I can't get them to bind again afterwards.
I put together a jsfiddle with a basic example. If you click the "Hover Off" button, mouseenter is disabled like intended. But then if you click the "Hover On" button after, mouseenter does not enable again.
http://jsfiddle.net/770b5p8q/3/
Here is "hover" functionality:
$('.square').each(function(){
$(this).bind("mouseenter", function(){
$(this).addClass('active');
});
$(this).bind("mouseleave", function(){
$(this).removeClass('active');
});
});
Here is what should enable/disable it:
$('.hover_enabled').click(function(){
$('.square').each(function(){
$(this).bind("mouseenter");
$(this).bind("mouseleave");
});
});
$('.hover_disabled').click(function(){
$('.square').each(function(){
$(this).unbind("mouseenter");
$(this).unbind("mouseleave");
});
});
You should pass the function for binding and unbinding the handlers, something like:
var mouseEnterHandler = function () {
$(this).addClass('active');
}
var mouseLeaveHandler = function () {
$(this).removeClass('active');
};
$('.square').bind("mouseenter", mouseEnterHandler)
.bind("mouseleave", mouseLeaveHandler);
$('.hover_enabled').click(function () {
$(this).addClass('active');
$('.hover_disabled').removeClass('active');
// I need to bind hover here
$('.square').bind("mouseenter", mouseEnterHandler)
.bind("mouseleave", mouseLeaveHandler);
});
But the code becomes ugly and unmaintainable. You can use event delegation instead:
$(document).on('mouseenter mouseleave', '.square.hoverable', function(event) {
// toggle the class by checking the type of the event
$(this).toggleClass('active', event.type === 'mouseenter');
});
// caching the state changers
var $e = $('.hover_enabled, .hover_disabled').click(function () {
var $this = $(this).addClass('active'),
isHoverable = $this.hasClass('hover_enabled');
// exclude the clicked element from the set and remove the class
$e.not($this).removeClass('active');
$('.square').toggleClass('hoverable', isHoverable);
});
The above mouseenter mouseleave handler is only executed when the .square element has hoverable className. You can also remove the event handler and use CSS for styling.
.square.hoverable:hover {
}
http://jsfiddle.net/bztec1f4/
Once you rebind it back you need to pass function as well.
$('.hover_enabled').click(function(){
$('.square').each(function(){
$(this).bind("mouseenter", function(){
$(this).addClass('active');
});
$(this).bind("mouseleave", function(){
$(this).removeClass('active');
});
});
});
Here is my code:
$(document).ready(function () {
var $div = $('<div>my test</div>').draggable().appendTo('body');
$div.attr('id', 'Test');
});
//$('div#Test'.draggable({
$('div').draggable({
stop: function (event, ui) {
var draggableId = $(this).attr("id");
alert(draggableId);
}
});
While dragging the dynamically div, I expected the stop function will show alert. But it not work. What am I doing wrong?
Thank you in advance for the help!
When you create your div element you call draggable on it, but without any settings. Try this:
var draggableSettings = {
stop: function (event, ui) {
var draggableId = $(this).attr("id");
alert(draggableId);
}
}
$(document).ready(function () {
$('div').draggable(draggableSettings); // any pre-existing divs
// the dynamically created div
var $div = $('<div>my test</div>', { 'id': 'Test').draggable(draggableSettings).appendTo('body');
});
Note also that the call to draggable on load needs to be placed within the document ready handler.
Having a bit of trouble figuring out how to turn an event handler back on.
I'm trying to stop the function from executing multiple times before the animation is finished.
Here's a Fiddle:
http://jsfiddle.net/MkmnW/1/
Here's my code:
$("#buttons a").click(function () {
$('a').off();
// Remove class from current active
$("#buttons a").removeClass('active');
// Change class on clicked button
$(this).addClass("active");
// Hide Non-Clicked Content
$(".main_content").fadeOut("fast");
$("#content_container").slideUp("slow");
// Find Selected
var selected = $(this).attr("href");
// Show Selected
$("#content_container").slideDown("slow", function () {
$(selected).fadeIn("slow");
});
return false;
});
If i understand your example correctly you want to prevent the animation from running multiple times by removing the event.
If your removing the event you will not be able to click it again unless you attach your event again.
Here's an example based on your code: http://jsfiddle.net/MkmnW/4/
$(document).ready(function () {
$("#buttons a").click(function () {
$('a').off("click");
clickMenu(this);
return false;
});
function clickMenu(el){
// Remove class from current active
$("#buttons a").removeClass('active');
// Change class on clicked button
$(el).addClass("active");
// Hide Non-Clicked Content
$(".main_content").fadeOut("fast");
$("#content_container").slideUp("slow");
// Find Selected
var selected = $(this).attr("href");
// Show Selected
$("#content_container").slideDown("slow", function () {
$(selected).fadeIn("slow");
$("#buttons a").click(function () {
$('a').off("click");
clickMenu(this);
return false;
});
});
}
});
You can $(element).unbind('click'); for unbinding click events. The same with all the other types of events.
Then, you could bind them again with $(element).bind('click', function(evt) { ... });
In the case of animations, you can $(element).click(function(evt) { $(this).stop().fadeOut("fast").whatever... });
var bar = $('.div_layer_Class');
$('a.second_line').click(function() {
$(this).unbind('mouseout');
}).mouseover(function() {
bar.css('display','inline');
}).mouseout(function() {
bar.css('display','none');
});
now the issue with 'onBodyclick' when i click anywhere on body again i want to invoke mouseoutevent something like this
$('body').click(function() {
bar.css('display','none');
event.preventDefault();
});
when I do this it overlaps $('a.second_line').click(function() event. any idea how I can Achieve this.
http://jsfiddle.net/qGJH4/56/
In addition to e.stopPropagation(),
you can do 2 things:
make a variable to reference the mouseout event handler so you can re-bind it whenever the user clicks elsewhere to the body.
or
A variable to store to whether a.second_line is focused or not. Something like
var focused = false;
You code now will be:
var bar = $('.div_layer_Class');
var focused = false;
$('a.second_line').click(function(e) {
focused = true;
e.stopPropagation();
}).mouseover(function() {
bar.css('display','inline');
}).mouseout(function() {
if (!focused)
bar.css('display','none');
});
$(document).click(function(e){
bar.css('display','none');
focused = false;
});
Example here
Try changing your code to this
var bar = $('.div_layer_Class');
$('a.second_line').click(function(e) {
bar.addClass('on');
e.stopPropagation();
}).mouseover(function() {
bar.css('display','inline');
}).mouseout(function() {
if(!bar.hasClass('on'))
bar.css('display','none');
});
$(document).on('click',function(){
bar.removeClass('on');
bar.css('display','none');
//return false;
});
Two lines to look at, first, the e in function(e)
$('a.second_line').click(function(e) {
and the stop e.stopPropagation();
That basically stops any parent handlers being notified. Read here