This question already has answers here:
How do I detect a click outside an element?
(91 answers)
Closed 4 years ago.
This is not a new problem on stackoverflow, but I've tried everything without success.
I have a "popup" created with two divs. The parent ist the background and the child is the popup content. I want to hide the popup when the user clicks on the background (the parent).
It sounds extremly easy also for me but I can't achieve that.
This is my code and what I tried (it works exacly at the opposite way as I want):
let content = document.querySelector('.popup-content');
let popup = document.querySelector('.popup');
let button = document.querySelector('button');
button.onclick = () => {
popup.style.display = 'block';
content.onclick = e => {
if(e.target !== this) {
popup.style.display = 'none';
}
}
}
.popup {
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: hidden;
background-color: rgb(0,0,0);
background-color: rgba(0,0,0,0.4);
display: none;
}
.popup-content {
background-color: #fff;
margin: 10% auto;
padding: 20px;
border: 1px solid #888;
width: 25%;
min-width: 470px;
border-radius: 4px;
}
<button>
Open Popup
</button>
<div class="popup">
<div class="popup-content">
<h3>Popup Title</h3>
<p>Popup Text</p>
</div>
</div>
Can somebody help me?
You should separate both events and attach the click to the window so you can detect the clicks outside of popup-content like :
let content = document.querySelector('.popup-content');
let popup = document.querySelector('.popup');
let button = document.querySelector('button');
button.onclick = () => {
popup.style.display = 'block';
}
window.onclick = e => {
if (e.target === popup) {
popup.style.display = 'none';
}
}
.popup {
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: hidden;
background-color: rgb(0, 0, 0);
background-color: rgba(0, 0, 0, 0.4);
display: none;
}
.popup-content {
background-color: #fff;
margin: 10% auto;
padding: 20px;
border: 1px solid #888;
width: 25%;
min-width: 470px;
border-radius: 4px;
}
<button>
Open Popup
</button>
<div class="popup">
<div class="popup-content">
<h3>Popup Title</h3>
<p>Popup Text</p>
</div>
</div>
you can try something like this :
instead of adding the EventListner to close the div on the button you need to add it on the document instead. and test on target if is not your button just like this :
let popup = document.querySelector('.popup');
let button = document.querySelector('button');
// Event that hide the popin if the click happen out popin
function closeHandler(e) {
if (e.target !== popup) {
// We remove the event for better perfermance
removeCloseListner();
// We hide the popin
popup.style.display = 'none';
}
}
// Call this function when you open your popin popin
function addCloseLitnerToDocument() {
document.addEventListener("click", closeHandler);
}
function removeCloseListner() {
document.removeEventListener("click", closeHandler)
}
// Add listner to Open Popin
button.onclick = (e) => {
e.preventDefault();
e.stopPropagation();
// when popin is open
// Add listner to the document
// And show the popin
popup.style.display = 'block';
addCloseLitnerToDocument();
}
Related
I got the following simple page.
<style>
#notifier {
position: fixed;
width: 320px;
bottom: 0;
left: 0;
padding: 10px;
}
#notification-silo {
width: 300px;
height: 100%;
position: relative;
}
#notification-silo .notification {
position: absolute;
bottom: 0;
width: 300px;
background-color: #fff;
box-shadow: 2px 2px 8px 2px #666;
}
#notification-silo .header {
background-color: #1266AB;
color: #fff;
padding: 5px;
}
#notification-silo .error .header {
background-color: #1266AB;
}
#notification-silo .warning .header {
background-color: #ff8f5f;
}
#notification-silo .header .title {
width: 260px;
display: inline-block;
}
#notification-silo .header .close-wrapper {
display: inline-block;
}
#notification-silo .header .close-wrapper button {
height: 25px;
width: 25px;
background-color: #2277bb;
border: 0;
color: #ff8f5f;
border-radius: 50%;
}
#notification-silo .warning .header .close-wrapper button {
background-color: #ffaa77;
color: #2277bb;
}
#notifier .body {
padding: 5px;
border: 1px solid lightgray;
}
</style>
<div id="notifier">
<div id="notification-silo">
</div>
</div>
<script>
function show(html) {
let notification, notificationArray, body, closeButton, existingNotificationHeights, sum, bottom, notification_template, siloElement, marginBetweenNotifications;
siloElement = document.querySelector("#notification-silo");
notification_template = `<div class="notification">
<div class="header">
<div class="title">Message</div>
<div class="close-wrapper">
<button>X</button>
</div>
</div>
<div class="body"></div>
</div>`;
marginBetweenNotifications = 10;
// calculate position
existingNotificationHeights = [...siloElement.children].map(notification => notification.offsetHeight);
sum = existingNotificationHeights.length ? existingNotificationHeights.reduce((a, b) => a + b) : 0;
bottom = sum + existingNotificationHeights.length * marginBetweenNotifications;
// creat elements by update innerHTML
siloElement.innerHTML += notification_template.trim();
notificationArray = [...siloElement.querySelectorAll(".notification")];
notification = notificationArray[notificationArray.length - 1];
notification.style.bottom = bottom + "px";
body = notification.querySelector(".body");
body.innerHTML += html;
// add event listener to close button
closeButton = notification.querySelector(".close-wrapper button");
closeButton.addEventListener("click", (ev) => {
console.log("click is fired");
});
};
show("System message 1");
show("System message 2");
show("System message 3");
show("System message 4");
show("System message 5");
</script>
It meant to create simple notification messages through show(msg) function. Here is the interesting part - when create few messages and try to add event listener to their close buttons, only the last button get a listener and actually listen for click event. All other close buttons do not react to mouse click. Can you please help me to understand why?
only you have to get close button reference object
show("System message 1");
show("System message 2");
show("System message 3");
show("System message 4");
show("System message 5");
[].forEach.call(document.querySelectorAll("#notification-silo button.close-wrapper"),function(el){
el.addEventListener("click",function(ev){
var targetElement = ev.target || ev.srcElement;
console.log(targetElement); //reference of button...
});
});
OR
<div class="close-wrapper">
<button onClick="Close(this)">X</button>
</div>
OR Perfect as One Standard Way don't use static html template string use dynamic pure JavaScript based element create method
example :
let mainDiv = document.querySelector("#notification-silo");
let aTag = document.createElement('a');
aTag.innerHTML = "CLOSE TEXT....";
aTag.addEventListener("click", (ev) => {
console.log("click is fired");
});
mainDiv.appendChild(aTag);
Quoting ProGu:
I guess siloElement.innerHTML += notification_template.trim() wipes
off the html content and re-assigned again, so previous events are
removed.
This question already has answers here:
What do querySelectorAll and getElementsBy* methods return?
(12 answers)
Closed 3 years ago.
I have written a simple JavaScript event listener for a JavaScript program I am currently building- I have written a simple modal which opens and closes on click but the on click does not seem to work. I am looping through JSON to display items for an eCommerce project as I am creating a new div for every new image could this be as to why the modal feature is not working?
var parentDiv = document.getElementsByClassName('items')
for (let i = 0; i < garments.hits.length; i++) {
const child = document.createElement('div')
child.setAttribute('class', 'style')
const image = document.createElement('img')
if (garments.hits[i].image) {
image.setAttribute('src', garments.hits[i].image.link)
image.setAttribute('alt', garments.hits[i].image.alt)
}
child.appendChild(image)
parentDiv[0].appendChild(child)
image.style.cssText = "height:550px; width:400px; cursor: pointer;"
// function for modal bit
var modal = document.getElementById('simpleModal');
// get open modal
var modalbtn = document.getElementsByClassName('style');
// get close button
var closeBtn = document.getElementsByClassName('closeBtn');
// listen for click event
modalbtn.addEventListener('click', openModal);
// function to open modal
function openModal() {
modal.style.display = 'block';
}
.modal {
position: fixed;
z-index: 1;
left: 0;
top: 0;
height: 100%;
width: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.719);
display: none;
}
.modal-content {
background-color: #f4f4f4;
margin: 20% auto;
padding: 20px;
width: 70%;
box-shadow: 0 5px 8px rgba(0, 0, 0, 0.2), 0 7px 20px rgba(0, 0, 0, 0.2);
}
.closeBtn {
color: #ccc;
float: right;
font-size: 30px;
}
.closeBtn:hover,
.closeBtn:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}
<div class="items">
<div id="simpleModal" class="modal">
<div class="modal-content">
<span class="closeBtn">×</span>
<p>?</p>
</div>
</div>
</div>
Here var modalbtn = document.getElementsByClassName('style');, modal button is a collection of elements. Therefore , modalbtn.addEventListener('click', openModal); wont work here.
Add
var modalbtn = document.getElementsByClassName('style');
modalbtn.forEach(function(button){
// listen for click event
button.addEventListener('click', openModal);
})
This will iterate through the elements and attach click event to it.
I have got code like below:
Now I would like to add functionality that increase the counter not only when I leave the box/square, BUT ALSO click the left mouse button outside the box/square. So the counter will be increasing only when the mouse leave the box/square and also click outside of the box/square.
var counter = 0;
function myLeaveFunction() {
document.getElementById("demo").innerHTML = counter += 1;
}
div {
width: 100px;
height: 100px;
border: 1px solid black;
margin: 10px;
float: left;
padding: 30px;
text-align: center;
background-color: lightgray;
}
<div onmouseleave="myLeaveFunction()">
<p>onmouseleave: <br> <span id="demo">Mouse over and leave me AND CLICK OUTSIDE THE BOX!</span></p>
</div>
Add a boolean to check if mouse had left the div and bind a click handler to the document:
var counter = 0;
var mouseLeft = false;
function myLeaveFunction() {
document.getElementById("demo").innerHTML = counter+=1;
mouseLeft = true;
}
function clickBody() {
if (mouseLeft == true)
document.getElementById("demo").innerHTML = counter+=1;
mouseLeft = false;
}
document.onclick = clickBody;
This example will add an event listener to the body when the mouse leaves the box and will increase the counter when a click event occurs. The new event listener is then removed:
var counter = 0;
function myLeaveFunction() {
document.body.addEventListener("click", myClickHandler);
function myClickHandler() {
document.getElementById("demo").innerHTML = counter += 1;
document.body.removeEventListener("click", myClickHandler);
}
}
body {
margin: 0;
height: 100vh;
width: 100%;
}
div {
width: 100px;
height: 100px;
border: 1px solid black;
margin: 10px;
float: left;
padding: 30px;
text-align: center;
background-color: lightgray;
}
<body>
<div onmouseleave="myLeaveFunction()" onclick="event.stopPropagation()">
<p>onmouseleave: <br> <span id="demo">Mouse over and leave me AND CLICK OUTSIDE THE BOX!</span></p>
</div>
</body>
JSFiddle if this doesn't work
Like this?
Once you left the box AND you click outside of it. The counter will be increased.
var showPopup = function (id) {
document.getElementById(id).style.display = "block";
}
var hidePopup = function (id) {
document.getElementById(id).style.display = "none";
}
// Button Click
document.getElementById('myButton').onclick = (ev) => {
showPopup('myPopup');
ev.stopPropagation(); // prevent immediate close (because button is "outside" too)
}
// Click outside to close popup
document.getElementsByTagName('body')[0].onclick = (ev) => {
let popup = document.getElementById('myPopup');
if( ev.path.indexOf(popup) == -1 ) { hidePopup('myPopup') }
};
hidePopup('myPopup');
body {
width: 100vw;
height: 100vh;
}
div {
width: 100px;
height: 100px;
border: 1px solid black;
padding: 30px;
text-align: center;
background-color: lightgray;
position: absolute;
margin: 10px;
display: none;
}
<div id='myPopup'>
<p>onmouseleave: <br> <span id="demo">Mouse over and leave me AND CLICK OUTSIDE THE BOX!</span></p>
</div>
<button id='myButton'>Show!</button>
Take a look
This may be helful too Bootstrap Modal
See this fiddle. This is my watch trailer button, the first button is working perfectly fine. But the second watch trailer button is not working.
What is the problem with it?
Here is my code:
HTML:
<button id="watchbutton">Watch Trailer ►</button>
<br>
<button id="watchbutton">Watch Trailer ►</button>
<div id="close">
<div id="trailerdivbox">
<div class="videoWrapper">
<iframe id="video" class="trailervideo" width="560" height="315" data-
src="https://www.youtube.com/embed/TDwJDRbSYbw" src="about:blank" frameborder="0" allowfullscreen></iframe>
</div>
</div>
</div>
CSS:
/* Watch Trailer Button CSS */
#watchbutton {
background-color: #f2f2f2;
color: red;
font-weight: 600;
border: none;
/* This one removes the border of button */
padding: 10px 12px;
}
#watchbutton:hover {
background-color: #e2e2e2;
cursor: pointer;
}
#trailerdivbox {
display: none;
width: 100%;
height: 100%;
position: fixed;
top:0%;
overflow: auto; /* Enable Scrolling */
background-color: rgb(0, 0, 0);
/* Fallback color */
background-color: rgba(0, 0, 0, 0.4);
/* Black w/ opacity */
}
.videoWrapper {
position: relative;
padding-bottom: 56.25%;
/* 16:9 */
padding-top: 25px;
height: 0;
}
.videoWrapper iframe {
position: absolute;
max-width: 560px;
max-height: 315px;
width: 95%;
height: 95%;
left: 0;
right: 0;
margin: auto;
}
Javascript
<script>
// Get the modal
var modal = document.getElementById('trailerdivbox');
// Get the button that opens the modal
var btn = document.getElementById("watchbutton");
function playVideo() {
var video = document.getElementById('video');
var src = video.dataset.src;
video.src = src + '?autoplay=1';
}
function resetVideo() {
var video = document.getElementById('video');
var src = video.src.replace('?autoplay=1', '');
video.src = '';
video.src = src;
}
// When the user clicks the button, open the modal
btn.onclick = function() {
modal.style.display = "block";
playVideo();
}
var trailerbox = document.getElementById("close");
trailerbox.onclick = function() {
modal.style.display = "none";
resetVideo();
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
resetVideo();
}
}
</script>
you can not have same ids. change id to something else.
<button id="watchbutton">Watch Trailer ►</button>
<br>
<button id="watchbutton2">Watch Trailer ►</button>
Try with classname instead of id .Because id is unique for whole html .For selector use with querySelectorAll()
Updated
declare src of the video in the data-src of button .Then pass the argument with playvideo(this.dataset.src) function .
// Get the modal
var modal = document.getElementById('trailerdivbox');
// Get the button that opens the modal
var btn = document.querySelectorAll('.watchbutton')
function playVideo(src) {
var video = document.getElementById('video');
video.src = 'https://www.youtube.com/embed/'+src + '?autoplay=1'; //add with iframe
}
function resetVideo() {
var video = document.getElementById('video');
var src = video.src.replace('?autoplay=1', '');
video.src = '';
video.src = src;
}
// When the user clicks the button, open the modal
btn.forEach(function(a){
a.onclick = function() {
modal.style.display = "block";
playVideo(this.dataset.src); // pass the src
}
})
var trailerbox = document.getElementById("close");
trailerbox.onclick = function() {
modal.style.display = "none";
resetVideo();
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
resetVideo();
}
}
/* Watch Trailer Button CSS */
#watchbutton {
background-color: #f2f2f2;
color: red;
font-weight: 600;
border: none;
/* This one removes the border of button */
padding: 10px 12px;
}
#watchbutton:hover {
background-color: #e2e2e2;
cursor: pointer;
}
#trailerdivbox {
display: none;
width: 100%;
height: 100%;
position: fixed;
overflow: auto;
/* Enable Scrolling */
background-color: rgb(0, 0, 0);
/* Fallback color */
background-color: rgba(0, 0, 0, 0.4);
/* Black w/ opacity */
}
.videoWrapper {
position: relative;
padding-bottom: 56.25%;
/* 16:9 */
padding-top: 25px;
height: 0;
}
.videoWrapper iframe {
position: absolute;
max-width: 560px;
max-height: 315px;
width: 95%;
height: 95%;
left: 0;
right: 0;
margin: auto;
}
<button id="watchbutton" class="watchbutton" data-src="TDwJDRbSYbw">Watch Trailer ►</button>
<br>
<button id="watchbutton" class="watchbutton" data-src="TDwJDRbSYbr">Watch Trailer ►</button>
<div id="close">
<div id="trailerdivbox">
<div class="videoWrapper">
<iframe id="video" class="trailervideo" width="560" height="315" data-src="https://www.youtube.com/embed/TDwJDRbSYbw" src="about:blank" frameborder="0" allowfullscreen></iframe>
</div>
</div>
</div>
<br>
You're almost there.
After you fix the issue with the double ids - mentioned by Frits, prasad & others - you still need to tell playVideo to play a different video, depending on which button you push.
Here's how you can fix your code to achieve the desired result :
// Get the modal
var modal = document.getElementById('trailerdivbox');
// Get the button that opens the modal
var btn1 = document.getElementById("TDwJDRbSYbw");
var btn2 = document.getElementById("6H_0aem12_I");
function playVideo(id) {
var video = document.getElementById('video');
var src = video.dataset.src + id;
video.src = src + '?autoplay=1';
}
function resetVideo() {
var video = document.getElementById('video');
var src = video.src.replace('?autoplay=1', '');
video.src = '';
video.src = src;
}
// When the user clicks the button, open the modal
btn1.onclick = function(e) {
modal.style.display = "block";
playVideo(this.id);
}
btn2.onclick = btn1.onclick;
var trailerbox = document.getElementById("close");
trailerbox.onclick = function() {
modal.style.display = "none";
resetVideo();
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
resetVideo();
}
}
/* Watch Trailer Button CSS */
.btn {
background-color: #f2f2f2;
color: red;
font-weight: 600;
border: none;
/* This one removes the border of button */
padding: 10px 12px;
}
.btn:hover {
background-color: #e2e2e2;
cursor: pointer;
}
#trailerdivbox {
display: none;
width: 100%;
height: 100%;
position: fixed;
overflow: auto;
/* Enable Scrolling */
background-color: rgb(0, 0, 0);
/* Fallback color */
background-color: rgba(0, 0, 0, 0.4);
/* Black w/ opacity */
}
.videoWrapper {
position: relative;
padding-bottom: 56.25%;
/* 16:9 */
padding-top: 25px;
height: 0;
}
.videoWrapper iframe {
position: absolute;
max-width: 560px;
max-height: 315px;
width: 95%;
height: 95%;
left: 0;
right: 0;
margin: auto;
}
<button class="btn" id="TDwJDRbSYbw">Watch Trailer ►</button>
<br>
<button class="btn" id="6H_0aem12_I">Watch Trailer ►</button>
<div id="close">
<div id="trailerdivbox">
<div class="videoWrapper">
<iframe id="video" class="trailervideo" width="560" height="315" data-src="https://www.youtube.com/embed/" src="about:blank" frameborder="0" allowfullscreen></iframe>
</div>
</div>
</div>
<br>
See also this JSFiddle demo
First, It is not good practice to use identical ids.
<button id="watchbutton">Watch Trailer ►</button>
And when you use
var btn = document.getElementById("watchbutton");
You get only one button (the first), You should use something like:
<button id="watchbutton" class="watchButton">Watch Trailer ►</button>
<br>
<button id="watchbutton2" class="watchButton" >Watch Trailer ►</button>
And get them with:
var buttons = document.getElementsByClassName("watchButton");
I'm currently designing a website in which a user clicks on a button and an overlay and box fades in with various contents. When the user either clicks a close button or clicks outside the box, the box and all the contents fade out. Here's a little bit of code I've already produced:
HTML
<div id="overlay"></div>
<div id="specialBox">
<p style="text-align: center">Special box content.</p>
<button type="button" onmousedown="toggleOverlay()">Close Overlay</button>
</div>
CSS
div#overlay {
background: #000;
display: none;
height: 100%;
left: 0px;
position: fixed;
text-align: center;
top: 0px;
width: 100%;
z-index: 2;
}
div#specialBox {
background: #fff;
color: #000;
display: none;
position: absolute;
z-index: 3;
margin: 150px auto 0px auto;
width: 500px;
height: 300px;
left: 425px;
}
JavaScript
function toggleOverlay(){
var overlay = document.getElementById('overlay');
var specialBox = document.getElementById('specialBox');
overlay.style.opacity = .8;
if(overlay.style.display == "block"){
overlay.style.display = "none";
specialBox.style.display = "none";
} else {
overlay.style.display = "block";
specialBox.style.display = "block";
}
}
jQuery (may be incorrect syntax)
$('html').click(function() {
if (document.getElementById('#specialBox').***IS_VISIBLE***) {
$("#specialBox").fadeOut(300);
$("#overlay").fadeOut(300);
}
});
An example can be found on http://www.madeon.fr when you click on "Newsleter". You can both click a close button and click outside to close it. Now, my question is how can I achieve that with my work?
I figured out the main problem. I simply deleted my jQuery and added "onmousedown='toggleOverlay()'" as an attribute to div#overlay. Then when I clicked the overlay the box disappeared.
Here's the new HTML:
<div id="overlay" onmousedown="toggleOverlay()"></div>
You can do it this way: using $(document).click
The below jsfiddle is for your help: http://jsfiddle.net/jec7rmw6/2/
function toggleOverlay(){
if($("#specialBox").is(":visible"))
{
$('#specialBox').fadeOut(300);
}
}
jQuery('#specialBox').click(
function (e) {
e.stopPropagation();
}
);
$(document).click(function() {
if($("#specialBox").is(":visible"))
{
$('#specialBox').fadeOut(300);
}
});