I have the following code that detects if a user is hovering over a box:
var toolTipHover = false;
$('#chartTooltip').on('mouseover', function () {
toolTipHover = true;
}).on('mouseout', function () {
toolTipHover = false;
});
$('.box').on('mouseover', function () {
$('#chartTooltip').show();
}).on('mouseout', function () {
console.log(toolTipHover);
if (!toolTipHover) {
$('#chartTooltip').hide();
}
toolTipHover = false;
});
And if they are then it shows the #chartTooltip element. (The tooltip is positioned and populated via some other means.)
However if the user hovers the tooltip itself it causes the tooltip to disappear (because they are no longer hovering the box). So I'm trying to check if the tooltip is being hovered (i.e. the next element hovered). and if so then ignore the mouseout event.
But toolTipHover is always false. I presume due to a race exception where mouseout has completed before the mouseover for the #chartTooltip can return the variable value of true.
How can I get around this?
I'm going to assume #chartToolTip is outside of .box for this. Instead of a flag variable (toolTipHover), just check the mouseleave event toElement property. So for example:
$('.box').on('mouseleave', function(e){
if (!$(e.toElement).is('.tooltip')){
$('.tooltip').hide();
}
})
Here is an example: https://jsfiddle.net/qvqafyf2/
$('.tooltip').hide();
$('.box').on('mouseover', function(e){
$('.tooltip').show();
})
$('.box').on('mouseleave', function(e){
if (!$(e.toElement).is('.tooltip')){
$('.tooltip').hide();
}
})
$('.tooltip').on('mouseleave', function(e){
if (!$(e.toElement).is('.box')){
$(this).hide();
}
})
.box{
width: 200px;
height: 200px;
background: red;
}
.tooltip{
height: 50px;
width: 50px;
background: green;
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">
</div>
<div class="tooltip">
hi
</div>
You could add #chartTooltip with .box in your function like this:
$('.box , #chartTooltip').on('mouseover', function()
here is fiddle
Related
My question in the title probably looks vague. And I sketched an example for the question:
container.onclick = () => {
alert(0);
};
content.onclick = () => {
alert("how can I prevent here appearance alert(0) from parent element event?");
//how can I prevent parent event by content clicked?
};
#container{
height: 100px;
background-color: gray;
}
#content{
height: 50px;
width: 150px;
background-color: green;
}
<div id="container">
<div id="content"></div>
</div>k
This is a simple example. In a real project, I can't combine these two events into one, because the first one is programmatically assigned somewhere in the bowels of my framework and it shouldn't be removed from the EventListener after clicking on content
In General, is it possible to somehow interrupt the execution of the call chain event by clicking in the DOM layers? I tried to do this:
content.onclick = () => {
alert("how can I prevent here appearance alert(0) from parent element event?");
e.preventDefault();
return false;
//how can I prevent parent event by content clicked?
};
But this, of course, was not successful
You should pass the event by dependency injection to the specific method (content.onclick) and then stop the propagation of it.
container.onclick = () => {
alert(0);
};
content.onclick = (e) => {
e.stopPropagation();
alert("VoilĂ , this prevent that appears alert(0) from parent element event.");
};
#container{
height: 100px;
background-color: gray;
}
#content{
height: 50px;
width: 150px;
background-color: green;
}
<div id="container">
<div id="content"></div>
</div>
For this, you can use stop propogation of js like this
<div id="container">
<div id="content" onclick="event.stopPropagation();">
</div>
</div>
So when you click on content it will not trigger container event only.
I've put this in the simplest terms for this question.
if element is clicked, 'active' class is added to element, 'active' class is removed from other elements.
However, if the element is 'active' and it's clicked for a second time the 'active' class should not be "re-applied" (or called for a second time).
$(".class").click(function(){
$('.class').not(this).removeClass('active');
$(this).addClass('active');
}
For example when button 1 is clicked and has the 'active' class -> doFunction;
if ( $(".active").is("#1") ) {
doFunction();
}
when it's clicked again, a second time, the function is fired again even though the element is already 'active'. If the element is active and is clicked a second time I don't want to call the functions again. How can I achieve this?
Codepen Example: https://codepen.io/anon/pen/yvZXOB?editors=1111
Thanks!
Since you didn't specify exactly how you want to limit the functions from being called, let's look at two possibilities.
First possibility: each button you can click to activate and call some function at most one time. After that, toggling buttons will toggle the classes but not calling the other function again.
In this scenario, you can use jQuery's .one().
$(".class").one('click', function(){
$('.class').not(this).removeClass('active');
$(this).addClass('active');
if ( $(".active").is("#1") ) {
doFunction();
}
if ( $(".active").is("#2") ) {
doFunction();
}
function doFunction() {
console.log("function fired!");
}
});
.class {
padding: 10px;
border-radius: 5px;
background: #392;
width: 100px;
color: white;
text-align: center;
margin: 25px;
display: inline-block;
cursor: pointer;
}
.active {
background: #932;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="class" id="1">
button
</div>
<div class="class" id="2">
another
</div>
Second possibility: when you click between buttons, the active state is toggled, but clicking a button that's already active won't keep running the other function. However, toggling away from a button and back to it will allow that button's function to run again.
In this case, you can set some kind of flag via a variable and then check the flag to see if you're allowed to run the other function again. Function runs, flag goes up. Different button gets clicked, flag goes back down.
var preventFunction;
$(".class").on('click', function(){
if($(this).hasClass('active')) {
preventFunction = true;
} else {
preventFunction = false;
}
$('.class').not(this).removeClass('active');
$(this).addClass('active');
if ( $(".active").is("#1") ) {
if(preventFunction !== true) {
doFunctionOne();
}
}
if ( $(".active").is("#2") ) {
if(preventFunction !== true) {
doFunctionTwo();
}
}
});
function doFunctionOne() {
console.log("function one fired!");
preventFunctiong = true;
}
function doFunctionTwo() {
console.log("function two fired!");
preventFunction = true;
}
.class {
padding: 10px;
border-radius: 5px;
background: #392;
width: 100px;
color: white;
text-align: center;
margin: 25px;
display: inline-block;
cursor: pointer;
}
.active {
background: #932;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="class" id="1">
button
</div>
<div class="class" id="2">
another
</div>
Since you are dynamically adding/removing classes, the correct apporach is to use event delegation like this:
$(document).on('click', ".class:not(.active)", function(){
$('.class').removeClass('active');
$(this).addClass('active');
console.log("click triggered!");
})
https://codepen.io/connexo/pen/PQVKNY?editors=1111
This trick will work(just use one global variable and hold the last active item's id),
var last_act_id = 0;
$(".class").click(function(){
if($(this).attr('id') != last_act_id) {
last_act_id = $(this).attr('id');
$('.class').removeClass('active');
$(this).addClass('active');
doFunction();
}
function doFunction() {
console.log("function fired!");
}
});
Demo: https://codepen.io/anon/pen/Nyovjr?editors=0001
Just check to see if that event target has the class already. Since you're using jQuery you could do something like
if($('.selector').hasClass('active')) {
$('.selector').removeClass('active')
} else {
$('.selector').addClass('active')
}
Try this
$("#1").click(function(){
$('#2').removeClass('active');
if (!$("#1").hasClass('active')) {
$("#1").addClass('active');
doFunction();
}else{
console.log("already clicked");
}
});
$("#2").click(function(){
$('#1').removeClass('active');
if (!$("#2").hasClass('active')) {
$("#2").addClass('active');
doFunction();
}else{
console.log("already clicked");
}
});
function doFunction() {
console.log("function fired!");
}
I hope it helps
When a user mouses over a div it should change to the color red, when they mouse out it should change back to transparent. When they click on the div, it should change to color red.
For some reason, the mouse out event listener is conflicting with the click event listener. Can someone help? When I click on the div, it doesn't change to red.
div$.on('mouseover', function () {
$(this).css('background-color', 'red');
});
div$.on('mouseout', function () {
$(this).css('background-color', 'white');
});
div$.on('click', function () {
$(this).css('background-color', 'red');
});
Note, I have to apply a background image dynamically to each element, so using CSS classes to add the background image is out of the question (because I don't know it before hand).
You could set a boolean variable to confirm that the click has occurred and then only run the mouseout code if the variable is false like this:
var is_clicked = false;
div$.on('mouseover', function () {
$(this).css('background-color', 'red');
});
div$.on('mouseout', function () {
if(!is_clicked) {
$(this).css('background-color', 'white');
}
});
div$.on('click', function () {
$(this).css('background-color', 'red');
is_clicked = true;
});
Note: For multiple div elements user multiple is_clicked variables
You can always do a CSS implementation with :hover; just make sure to add a specifying class to each element you would like this effect on.
1. :hover and jQuery
var div$ = $('.redHover'); // name the class whatever you like
div$.on('click', function () {
$(this).css('background-color', 'red');
});
div {
display: inline-block;
}
.redHover {
height: 100px;
width: 100px;
border: 1px solid black;
}
.redHover:hover {
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='redHover'></div>
<div class='redHover'></div>
<div class='redHover'></div>
2. :hover and vanilla JS
var els = document.querySelectorAll('.redHover');
for (var i = 0; i < els.length; ++i) {
els[i].addEventListener('click', function() {
this.style.backgroundColor = 'red';
});
}
div {
display: inline-block;
}
.redHover {
height: 100px;
width: 100px;
border: 1px solid black;
}
.redHover:hover {
background: red;
}
<div class='redHover'></div>
<div class='redHover'></div>
<div class='redHover'></div>
Instead use mouseenter insead of mouseover see why.
The best thing you can go with would be the following notes:
To those elements with hover effect add a class like hoverable.
Hover effect is only applied to those elements having this class.
HTML:
<div class="hoverable"></div>
CSS:
.hoverable:hover{
background-color: red
}
JavaScript:
div$.on('click', function () {
$(this).css('background-color', 'red');
});
In this way, you can simply decide whether an element should be hover-able or not by adding or removing hoverable class. Also hover effect is applied in CSS level not JavaScript, which is more acceptable.
As far as I understand you really want to change picture in the div, not just background color which is relatively easy. Try this:
<div class="hoverable">
<img src="myImg.jpg" />
</div>
//css
.hoverable img{visibility:hidden;}
.hoverable:hover img{visibility:visible;}
.clicked img{visibility:visible!important;}
//JS
$('.hoverable').click(function(){
$(this).addClass('clicked');
});
I'm trying to have an overlay that I can toggle with keyboard keys.
However, once I hide the menu using fade out, the document won't receive my keydown events until I click in the window. How can I make the document receive focus so that it will listen directly after fade out has finished?
<div id="overlay" class="overlay">
<input type="text" value="test"/>
</div>
$('#overlay').on('keydown', function() {
$('#overlay').fadeOut(1000);
return false;
});
$(document).on('keydown', function() {
$('#overlay').fadeIn(1000);
return false;
});
.overlay {
position: fixed;
background: black;
color: white;
width: 50%;
height: 100px;
}
See jsFiddle also
Put cursor in input field, press one key.
It should fade out over a second. After that document is not receiving any keydown until I click in it with the mouse. How can I make document receive focus so that I could toggle the modes with just one keyboard key?
Edit: Tested the fiddle in different browsers. This problem seems to be specific for chrome.
Remove focus from your text field after fading out your overlay
Working Fiddle
$(document).ready(function () {
$('#overlay').on('keyup', function () {
$('#overlay').fadeOut(1000);
$("input[type='text']").blur();
return false;
});
$('body').on('keyup', function () {
$('#overlay').fadeIn(1000);
return false;
});
});
http://jsfiddle.net/CCKUz/
So I have a box with a <span class="open"> that will increase the height of a collapsible div to view the content. It's collapsible simply by CSS height and the open click function sets height to auto. Easy and this works.
The problem happens when I go to append the open and close spans. When I include them in the actual html, they work fine. When I append them, they no longer function. I thought maybe this was due to not being available for the js to apply the .click function to them since they were created after the load but even creating them and applying the .click in the same function doesn't help this problem.
Is there anything you see there that might be affecting this? Thanks.
HTML:
<div class="box collapsible">
<h3>Title</h3>
<p>This is a sample paragraph that is here for placer purposes.</p>
</div>
CSS:
.box { height: 20px; border: 1px solid #000000; padding: 10px; margin: 20px; position: relative; overflow: hidden; }
h3 { margin: 0 0 20px 0; line-height: 20px; }
.open, .close { text-indent: -9999px; width: 20px; height: 20px; position: absolute; top: 10px; right: 10px; }
.open { background: #00ff00; }
.close { background: #0000ff; }
JS:
$(function(){
var box = $(".collapsible");
var close = $(".collapsible span.close");
var open = $(".collapsible span.open");
box.each(function(){
box.append('<span class="open">Open</span>');
open.each(function(i){
open.click(function(){
alert("You clicked open");
$(this).parent(box).css("height","auto").append('<span class="close">Close</span>');
$(this).hide();
$(this).parent().find(close).show();
});
});
close.each(function(i){
close.click(function(){
$(this).parent(box).css("height","15px");
$(this).hide();
$(this).parent().find(open).show();
});
});
});
});
No need for loops, jQuery does that internally, and you need delegated event handlers with dynamic elements, like so:
$(function () {
var box = $(".collapsible");
box.append( $('<span />', {'class':'open'}) )
.on('click', '.close', function () {
$(this).hide()
.closest('.collapsible')
.css("height", "auto")
.append( $('<span />', {'class':'close'}).show() );
})
.on('click', '.close', function () {
$(this).hide()
.closest('.collapsible')
.css("height", "15px")
.find('.open').show();
});
});
you select the open-elements before adding them:
var open = $(".collapsible span.open");
Try this:
$(function(){
var box = $(".collapsible");
var close = $(".collapsible span.close");
box.each(function(){
box.append('<span class="open">Open</span>');
var open = $(".collapsible span.open"); //do it here!!
open.each(function(i){
open.click(function(){
alert("You clicked open");
$(this).parent(box).css("height","auto").append('<span class="close">Close</span>');
$(this).hide();
$(this).parent().find(close).show();
});
});
close.each(function(i){
close.click(function(){
$(this).parent(box).css("height","15px");
$(this).hide();
$(this).parent().find(open).show();
});
});
});
});
There is no need for .each delegate the function
$(document).on('click','.collapsible span.open',function(){
demo here http://jsfiddle.net/CCKUz/2/
The problem is that you are adding your .close spans dynamically, so your initial search will not find anything, so it will not add any click handlers to them. You can use event delegation to fix this easily.
.on('click', 'span.close', function(evt){
You can also simplify your code a lot:
$(".collapsible")
.append('<span class="open">Open</span>')
.on('click', 'span.open', function(evt){
// Search within the parent '.collapsible'.
$(evt.delegateTarget)
.css("height", "auto")
.append('<span class="close">Close</span>');
// Hide the '.open' span.
$(this).hide();
})
.on('click', 'span.close', function(evt){
// Search within the parent '.collapsible'.
$(evt.delegateTarget)
.css("height","15px");
.find('.open').show();
// Remove the old '.close' button since the
// open handler will make a new one.
$(this).remove();
})