close overlay except if "special" Div is clicked with jQuery/Javascript - javascript

I have a div called "MyDiv". When this div is clicked an overlay is shown with a "MyDiv_subDiv" appended. When user clicks on the overlay the view should disappear but NOT if iser clicks on "MyDiv_subDiv".
I've found a similar question here and tried it out, here is my code:
var $MyDiv = $('#MyDiv');
var $overlay = $('<div id="overlay"></div>');
var $MyDiv_subDiv = $('<div id="MyDiv_subDiv" class="subDiv">\n\
<div class="subDivContent">\n\
<div class="subDivContent">\n\
<p>some content</p>\n\
</div>\n\
</div>\n\
</div>');
//Add overlay
$("body").append($overlay);
//When overlay is clicked
$overlay.click(function () {
//Hide the overlay
$overlay.hide();
$overlay.empty();
});
$MyDiv.click(function (event) {
event.preventDefault();
$overlay.show();
$overlay.append($MyDiv_subDiv);
});
$MyDiv_subDiv.click(function (event) {
event.stopPropagation();
});
#overlay {
background:rgba(0,0,0,0.7);
width:100%;
height:100%;
position:absolute;
top:0;
left:0;
display:none;
text-align:center;
}
.subDiv{
width: 400px;
height: 125px;
margin: 0 auto;
}
#MyDiv_subDiv{
background-color: lightgreen;
}
#MyDiv{
width: 185px;
height: 80px;
background-color: lightgray;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="MyDiv">
Click to show MyDiv_SubDiv
</div>
The problem is: It only works when "MyDiv" is clicked first time. When overlay is closed and "MyDiv" is clicked second time and then click on "MyDiv_subDiv" it disappears - and it shouldn't!
Any help is appreciated!

From jquery.empty
To avoid memory leaks, jQuery removes other constructs such as data
and event handlers from the child elements before removing the
elements themselves.
If you want to remove elements without destroying their data or event
handlers (so they can be re-added later), use .detach() instead.
So you have to use .detach to keep the event.
And as .detach is apply on self, not on child, you have to change
$overlay.empty(); to $MyDiv_subDiv.detach(); or $overlay.children().detach();
or you can rebind the event everytime you append it to $overlay.
var $MyDiv = $('#MyDiv');
var $overlay = $('<div id="overlay"></div>');
var $MyDiv_subDiv = $('<div id="MyDiv_subDiv" class="subDiv">\n\
<div class="subDivContent">\n\
<div class="subDivContent">\n\
<p>some content</p>\n\
</div>\n\
</div>\n\
</div>');
//Add overlay
$("body").append($overlay);
//When overlay is clicked
$overlay.click(function () {
//Hide the overlay
$overlay.hide();
$overlay.children().detach();
});
$MyDiv.click(function (event) {
event.preventDefault();
$overlay.show();
$overlay.append($MyDiv_subDiv);
});
$MyDiv_subDiv.click(function (event) {
event.stopPropagation();
});
#overlay {
background:rgba(0,0,0,0.7);
width:100%;
height:100%;
position:absolute;
top:0;
left:0;
display:none;
text-align:center;
}
.subDiv{
width: 400px;
height: 125px;
margin: 0 auto;
}
#MyDiv_subDiv{
background-color: lightgreen;
}
#MyDiv{
width: 185px;
height: 80px;
background-color: lightgray;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="MyDiv">
Click to show MyDiv_SubDiv
</div>

Related

Open a div by clicking and close by clicking outside of it

A div is initially hidden, I want to display it when clicking a button. And once it is visible, I want to hide it when clicking anywhere outside that div.
I'm trying following code, it displays the div, but the problem is in the second part (clicking outside) the box. The second part conflicts with first one so it hides it before displaying.
How can I fix that?
$('button').on('click', function(e){
e.preventDefault();
$('.box').addClass('active');
});
//hide is by clicking outside .box
$(document).on('click', function (e) {
if ($('.box').is(':visible') && !$('.box').is(e.target) && !$('.box').has(e.target).length) {
$('.box').hide();
}
});
button {
margin-bottom: 20px;
}
.box {
width: 200px;
height: 120px;
background: #fab1a0;
display: none;
}
.active {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button>Click</button>
<div class="box"></div>
You can stop the propagation of your event so that when button is clicked the event doesn't bubble up to the document. Also instead of hide(), just using removeClass(...) should work for you.
Also that event propagation doesn't stop in this button listener itself but from the next event listener which in your case is on the document and that is what we require.
$('button').on('click', function(e){
e.stopPropagation();
$('.box').addClass('active');
});
//hide is by clicking outside .box
$(document).on('click', function (e) {
if ($('.box').is(':visible') && !$('.box').is(e.target) && !$('.box').has(e.target).length) {
$('.box').removeClass('active');
}
});
button {
margin-bottom: 20px;
}
.box {
width: 200px;
height: 120px;
background: #fab1a0;
display: none;
}
.active {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button>Click</button>
<div class="box"></div>

Toggle won't stay open

I have images (.rv_button) that are acting as buttons to toggle the div's below (#reveal). I want to hover over the button to open the div but right now I can't get the div to stay open. Can someone help me with this?
jQuery(document).ready(function() {
// Hide the div
jQuery('#reveal').hide();
jQuery('.rv_button').on('mouseenter mouseleave', function(e) {
e.preventDefault();
jQuery("#reveal").fadeToggle()(slow, swing, callback);
jQuery('.rv_button').toggleClass('open');
});
});
Rather than using toggleClass(), on mousenter, remove the open class from all of the buttons and add it to e.target or $(this). And on mouseout just remove it from all the buttons.
Also, remove (slow, swing, callback) or use them as arguments in fadeToggle().
e.g.
jQuery("#reveal").fadeToggle('slow');
And to keep the div to stay open, just wrap the buttons and div in a container and listen for the mouseout event on it instead of the buttons themselves.
$(document).ready(function() {
// Hide the div
$('#reveal').hide();
$('.rv_button').on('mouseenter', function(e) {
e.preventDefault();
$('.rv_button').removeClass('open');
$(e.target).addClass('open');
$("#reveal").fadeIn();
});
$('.container').on('mouseleave', function(e) {
e.preventDefault();
$('.rv_button').removeClass('open');
$("#reveal").fadeOut();
});
});
.container {
width: 400px;
}
#reveal {
width: 400px;
height: 400px;
background-color: beige;
text-align: center;
font-size: 2em;
}
.rv_button {
padding: 1em;
background-color: brown;
width: 400px;
box-sizing: border-box;
}
.open {
background-color: orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="rv_button">Button 1</div>
<div class="rv_button">Button 2</div>
<div class="rv_button">Button 3</div>
<div id="reveal">Reveal</div>
</div>

Click through full height element to empty space to add class

I want to remove .visible class when I click inside of the unfilled space of a full-height header.
Inside of the header I have .container that doesn't have full height.
When I click on the container or its links, it shouldn't remove the class but when I click on remaining space below container it should remove the class.
Is this possible with the given HTML and CSS?
https://codepen.io/rKaiser/pen/EeNoqR
$('body').on('click', '.button', function(){
$('body').toggleClass('visible');
});
$('.visible *:not(.container)').click(function() {
alert('clicked the outside');
$('body').removeClass('visible');
return false;
});
You can bind a click event to the <header>, another click event to its inner <div>, and stop the propagation of the event so that only the more specific one (the div) will be executed:
$( document ).ready(function() {
$('body').on('click', '.button', function(){
$('body').toggleClass('visible');
});
$('header').click(function() {
alert('clicked outside the container');
$('body').removeClass('visible');
return false;
});
$('.container').click(function(e){
alert ('clicked inside the container');
e.stopPropagation();
})
});
* {
padding:0;
margin:0;
}
body.visible header {
display:block;
}
header {
top: 0;
bottom: 0;
position: fixed;
overflow-y: scroll;
overflow-x: hidden;
background-color: rgba(0,0,0,.5);
display: none;
z-index: 999;
width: 100%;
overflow: visible;
}
.container {
background: #ccc;
padding:30px;
}
ul {
padding:0;
margin:0;
}
a {
display:block;
}
.button {
position:absolute;
top:0;
z-index:9999;
background: yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<body>
<div class="button">Button</div>
<header>
<div class="container">
<ul>
<li>asd</li>
<li>asdas</li>
<li>asdsa</li>
<li>asdasda</li>
</ul>
</div>
</header>
</body>
</html>
You should bind click to all elements and check if body has class in it:
$('body *:not(.container)').click(function() {
if($('body').hasClass('visible')){
alert('clicked the outside');
$('body').removeClass('visible');
return false;
}
});

unexpected jquery event behaviour from within contained div

I am seeing unexpected behaviour on a small HTML widget ive recently created. Three successively embedded divs each one has a marker and a menu which show up on entry into the div and hide on exit. The marker is intended to track the vertical mouse position. Problem here is that the mouseover event fires only when the mouse is over the marker and not when the mouse over the containing div.
http://jsfiddle.net/laurencefass/f47a7a2r/
$( ".outer, .inner, .middle" )
.mouseenter(function(e) {
$(this).children(".content:first").show();
$(this).parents().children(".content:first").hide();
$(this).children(".marker:first").show();
$(this).parents().children(".marker:first").hide();
})
.mouseleave(function(e) {
$(this).children(".content:first").hide();
$(this).parents().children(".content:first").show();
$(this).children(".marker:first").hide();
$(this).parents().children(".marker:first").show();
})
.mouseover(function(e) {
$(".content", $(this)).html("left = " + e.pageX + " right = " + e.pageY);
var marker = $(this).children(".marker");
marker.offset({top:e.pageY - marker.height()/2, right:0});});
.outer, .middle, .inner {
font-size:0.8em;
position:absolute;
border:5px solid black;
background-color:lightgray;
text-align:center;
}
.outer {
top:10%;
left:10%;
width:80%;
height:500%;
}
.middle {
top:5%;
left:20%;
width:60%;
height:60%;
}
.inner {
top:5%;
left:30%;
width:40%;
height:60%;
}
.content {
background-color:aliceblue;
min-height:2em;
min-width:50px;
display:none;
}
.marker {
height:50px;
width:5em;
background-color:black;
position:absolute;
right:0px;
margin-right:2px;
display:none;
color:white;
fontsize:0.8em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<div class="outer">
<div class="content">outer menu</div>
<div class="marker">widget</div>
<div class="middle">
<div class="content">middle menu</div>
<div class="marker">widget</div>
<div class="inner">
<div class="content">inner menu</div>
<div class="marker">widget</div>
</div>
</div>
</div>
This can be done much easier just using CSS. You can use this functionallity for your widgets too.
.outer:hover>.content,
.middle:hover>.content,
.inner:hover>.content{
display: block;
}
Then you can strip out your mouseenter and mouseleave
$( ".outer, .inner, .middle" )
.mouseover(function(e) {
var marker = $(this).children(".marker");
marker.offset({top:e.pageY - marker.height()/2, right:0});
});
JSFiddle
If you only want to show the widget of the element hovered you have to use jQuery, Furthermore you would probably use mosemove() event to have it at the mouse position all the time.
$( ".outer, .inner, .middle" ).mousemove(function(e) {
e.stopPropagation();
var marker = $(this).children(".marker");
marker.eq(0).show();
marker.offset({top:e.pageY - marker.height()/2, right:0});
});
$( ".inner, .middle" ).mouseenter(function(e) {
if($('.marker', $(this).parent()).eq(0).length){
$('.marker', $(this).parent()).eq(0).hide();
}
});
$( ".outer, .inner, .middle" ).mouseleave(function(e) {
if($('.marker', $(this).eq(0)).length){
$('.marker', $(this).eq(0)).hide();
}
});
JSFiddle
my expectation: a rhs "floating" widget to track the vertical position of the mouse and be visible only as long as the cursor is within scope of the marker's container.

Mouseover events of two DIVs, positioned one over the other

I need to trigger the mouseover event of two DIVs positioned one on top of other.
http://jsfiddle.net/hvh8k/
For the DIV in front, if I have given pointer-events:none; I will get the mouseover event of the DIV underneath. But this stops triggering the mouseover event of the DIV in front.
Javascript
$(function () {
var stopAnimation = false;
var loop1 = setInterval(function () {
if(stopAnimation)return;
var L = parseInt($("#back").css("left"), 10) + 10;
if(L > $(window).width())L=-300;
$("#back").css("left", L);
}, 100);
$("#back").mouseover(function () {
stopAnimation = true;
});
$("#back").mouseout(function () {
stopAnimation = false;
});
$("#front").mouseover(function () {
$("#front").animate({width:200}, 100);
});
$("#front").mouseout(function () {
$("#front").animate({width:100}, 100);
});
});
CSS
#back {
width: 300px;
height: 200px;
background-color: #aaa;
position: absolute;
left:0;
cursor: pointer;
}
#front {
width: 100px;
height: 100px;
background-color: #caa;
position: absolute;
left:0;
top:100px;
border-radius:50%;
overflow:hidden;
}
body {
margin:0;
}
HTML
<div id="main">
<div id="back"></div>
<div id="front"></div>
</div>
Don't know if this would be suited for what you are trying to achieve, but what about toggling the z-index as you click the divs?
First div.front will show. When div.front is clicked, it calls your function AND move div.front to the back, and div.back to the front, which would allow you to click and trigger the div.back function and toggle the divs again.
So to be clear... front visible > click > back visible > click > front visible etc.

Categories

Resources