Hide pop-up by clicking outside it (problems with Philip Waltons solution) - javascript

I know the question of closing a pop-up by clicking outside of it has been asked before. I have a somewhat complex pop-up and the solution offered by Phillip Walton isn't working for me.
His code simply made my page blurry but stopped the popup from appearing.
$(document).on('click', function(event) {
if (!$(event.target).closest('.maincontainer').length) {
popup.classList.remove('popup--open');
popup.style.display = 'none';
popupAccessory.style.display = 'none';
popupAccessory.classList.remove('popup--accessory--open');
maincontainer.classList.remove('blurfilter');
}
});
I also tried:
window.addEventListener('click', function(event) {
if (event.target != popup) {
popup.classList.remove('popup--open');
popup.style.display = 'none';
popupAccessory.style.display = 'none';
popupAccessory.classList.remove('popup--accessory--open');
maincontainer.classList.remove('blurfilter');
}
}, true);
This closes the popup when I click anywhere, including on the popup itself. I want it to close only when I click on part of the screen that isn't the popup.
The code to open the popup:
function openpopup() {
popup.style.display = 'initial';
setTimeout(function(){
popup.classList.add('popup--open');
popup.style.boxShadow = '0 0 45px 2px white';
maincontainer.classList.add('blurfilter')}, 10);
for (let i = 0; i < listitems.length; i++ ) {
setTimeout(function() {
listitems[i].classList.add('visible');
}, 100);
}
}
I added the event listener to a button
popupOpenbtn.addEventListener('click', openpopup);
The HTML structure:-
<div class="maincontainer>
...all my page content...
</div>
<div class="popup">
...popup contents...
</div

I would suggest using only css classes to style your popup and use JS only to add, remove and toggle that class. Not sure how close to your working exercise is this fiddle but I've prepared this to show how the document/window click event can be checked to successfully open/close the popup window.
var popupOverlay = document.querySelector('#popup__overlay');
var popupOpenButton = document.querySelector('#popupOpenButton');
var popupCloseButton = document.querySelector('#popupCloseButton');
var mainContainer = document.querySelector('main');
function closestById(el, id) {
while (el.id != id) {
el = el.parentNode;
if (!el) {
return null;
}
}
return el;
}
popupOpenButton.addEventListener('click', function(event) {
popupOverlay.classList.toggle('isVisible');
});
popupCloseButton.addEventListener('click', function(event) {
popupOverlay.classList.toggle('isVisible');
});
mainContainer.addEventListener('click', function(event) {
if (popupOverlay.classList.contains('isVisible') && !closestById(event.target, 'popup__overlay') && event.target !== popupOpenButton) {
popupOverlay.classList.toggle('isVisible');
}
});
#popup__overlay {
display: none;
background-color: rgba(180, 180, 180, 0.5);
position: absolute;
top: 100px;
bottom: 100px;
left: 100px;
right: 100px;
z-index: 9999;
text-align: center;
}
#popup__overlay.isVisible {
display: block;
}
main {
height: 100vh;
}
<aside id="popup__overlay">
<div class="popup">
<h2>Popup title</h2>
<p>
Lorem ipsum
</p>
<button id="popupCloseButton">Close popup</button>
</div>
</aside>
<main>
<div class="buttonWrapper">
<button id="popupOpenButton">Open popup</button>
</div>
</main>

Related

Toggle show/hide functions between multiple divs

I have a page on my site which has 3 separate 'hidden' divs. Each with it's own 'show/hide' button.
Currently... each div and button set functions independently.
Therefore... if all divs are shown (open) at the same time, they stack according to their respective order.
Instead of that, I would rather restrict the function a bit, so that only div can be shown (open) at a time.
Example: If Div 1 is shown, and the user then clicks the Div 2 (or Dive 3) button, Div 1 (or which ever div is open at the time, will close.
I am not sure how to adjust my code to make that all work together. I have tried a few ideas, but they were all duds. So I posted a generic 'independent' version below.
function show_Div_1() {
var div1 = document.getElementById("Div_1");
if (div1.style.display === "none") {
div1.style.display = "block";
} else {
div1.style.display = "none";
}
}
function show_Div_2() {
var div2 = document.getElementById("Div_2");
if (div2.style.display === "none") {
div2.style.display = "block";
} else {
div2.style.display = "none";
}
}
function show_Div_3() {
var div3 = document.getElementById("Div_3");
if (div3.style.display === "none") {
div3.style.display = "block";
} else {
div3.style.display = "none";
}
}
.div {
width: 270px;
height: 30px;
padding-left: 10px;
}
<button type="button" onclick="show_Div_1()">Div 1 - Red</button>
<button type="button" onclick="show_Div_2()" style="margin-left: 4px">Div 2 - Blue</button>
<button type="button" onclick="show_Div_3()" style="margin-left: 4px">Div 3 - Green</button>
<div id="Div_1" class="div" style="background-color:red; display: none;"></div>
<div id="Div_2" class="div" style="background-color:blue; display: none;"></div>
<div id="Div_3" class="div" style="background-color:green; display: none;"></div>
I would suggest using data attributes for a toggle. Why? you can use CSS for them and you can use more than just a toggle - multiple "values".
Here in this example I do your "click" but also added a double click on the button for a third value. Try some clicks and double clicks!
A bit of overkill perhaps but more than just "toggle" for example you could use this to show "states" of things like a stoplight or any number of things.
Use the grid display and move them by just adding a data attribute value and double click it to get it to go (using css) to some grid-area:, things like that.
const hideValues = {
hide: "hidden",
show: "showme",
double: "dblclick"
};
function dblClickHander(event) {
const targetSelecor = event.target.dataset.target;
const target = document.querySelector(targetSelecor);
const action = target.dataset.hideme == hideValues.double ? hideValues.hide : hideValues.double;
const toggleTargets = document.querySelectorAll('.toggle-target');
toggleTargets.forEach(el => {
el.dataset.hideme = hideValues.hide;
});
target.dataset.hideme = action;
}
function toggleEventHandler(event) {
const targetSelecor = event.target.dataset.target;
const target = document.querySelector(targetSelecor);
const showHide = target.dataset.hideme == hideValues.hide ? hideValues.show : hideValues.hide;
const toggleTargets = document.querySelectorAll('.toggle-target');
toggleTargets.forEach(el => {
el.dataset.hideme = hideValues.hide;
});
target.dataset.hideme = showHide;
}
/* set up event handlers on the buttons */
const options = {
capture: true
};
/* we do this first to prevent the click from happening */
const toggleButtons = document.querySelectorAll('.toggle-button');
toggleButtons.forEach(el => {
el.addEventListener('dblclick', dblClickHander, options);
});
toggleButtons.forEach(el => {
el.addEventListener('click', toggleEventHandler, options)
});
.toggle-target {
width: 270px;
height: 30px;
padding-left: 10px;
}
.toggle-target[data-hideme="hidden"] {
display: none;
}
.toggle-target[data-hideme="showme"] {
display: block;
}
.toggle-target[data-hideme="dblclick"] {
display: block;
border: solid 2px green;
padding: 1rem;
opacity: 0.50;
}
.red-block {
background-color: red;
}
.blue-block {
background-color: blue;
}
.green-block {
background-color: green;
}
<button type="button" class="toggle-button" data-target=".red-block">Div 1 - Red</button>
<button type="button" class="toggle-button" data-target=".blue-block">Div 2 - Blue</button>
<button type="button" class="toggle-button" data-target=".green-block">Div 3 - Green</button>
<div class="toggle-target red-block" data-hideme="hidden">red</div>
<div class="toggle-target blue-block" data-hideme="hidden">blue</div>
<div class="toggle-target green-block" data-hideme="hidden">green</div>
This can be done in many ways. I think the best approach in your case could be
BUTTONS
<button type="button" onclick="show_div('Div_1')">Div 1 - Red</button>
<button type="button" onclick="show_div('Div_2')" style="margin-left: 4px">Div 2 - Blue</button>
<button type="button" onclick="show_div('Div_3')" style="margin-left: 4px">Div 3 - Green</button>
SCRIPT
function show_div(div_id) {
var thisDiv = document.querySelector('#'+div_id);
var thisState = thisDiv.style.display;
// close all in any cases
document.querySelectorAll('.div').forEach(function(el) {
el.style.display = "none";
});
// open this div only if it was closed
if (thisState == "none" ){
thisDiv.style.display = "block";
}
}

display sticky div if within viewport

I am basing my code off of this SO thread.
I have a parent div that is half way down the page. Within that parent div I want to display a sticky footer div, but only when viewport is showing the parent div. I have tried 4 different tutorials so far with no luck.
The page structure is this:
HEADER
HERO
CONTENT RIGHT-SIDE(id="wrap-vs")
CONTENT-FULL-WIDTH
FOOTER
When RIGHT-SIDE is within view, I want to display a sticky div within it. You can't see RIGHT-SIDE when page loads, you need to scroll down to it. Also, when we are below it I want the sticky div to go away.
var targetdiv = document.querySelector('.tabs');
console.log(targetdiv);
targetdiv.style.display = "none";
function CheckIfVisible(elem, targetdiv) {
var ElemPos = elem.getBoundingClientRect().top;
targetdiv.style.display = (ElemPos > 0 && ElemPos < document.body.parentNode.offsetHeight) ? "block" : "none";
}
window.addEventListener("onscroll", function() {
var elem = document.querySelector('#wrap-vs');
CheckIfVisible(elem, targetdiv);
});
#wrap-vs {
height: 100%;
background-color: yellow;
}
.tabs {
position: fixed;
bottom: 0;
}
<div id="wrap-vs">
<div class="tabs">
right-side content sticky div
</div>
</div>
This is how I fixed it:
// Create a new observer
var observer = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
// Log if the element and if it's in the viewport
console.log(entry.isIntersecting);
if(entry.isIntersecting == true){
document.querySelector('.tabs').style.display = 'block';
} else {
document.querySelector('.tabs').style.display = 'none';
}
});
});
// The element to observe
var app = document.querySelector('#wrap-vs');
// Attach it to the observer
observer.observe(app);
#wrap-vs {
height: 100%;
background-color: yellow;
}
.tabs {
position: fixed;
bottom: 0;
}
<div id="wrap-vs">
<div class="tabs">
right-side content sticky div
</div>
</div>

jQuery - element crossing another element

I have a fixed div on the page which contains a logo and as the user scrolls and this logo passes over other divs I wnat to the change the colour of the logo.
I have this working over a single div but need to it work across multiple so any help appreciated.
The WIP site can be seen here... dd.mintfresh.co.uk - if you scroll down you'll (hopefully) see the logo change from black to white as it crosses an illustrated egg. I need the same to happen when it crosses other divs further down the page.
The script so far...
jQuery(window).scroll(function(){
var fixed = jQuery("logo");
var fixed_position = jQuery("#logo").offset().top;
var fixed_height = jQuery("#logo").height();
var toCross_position = jQuery("#egg").offset().top;
var toCross_height = jQuery("#egg").height();
if (fixed_position + fixed_height < toCross_position) {
jQuery("#logo img").css({filter : "invert(100%)"});
} else if (fixed_position > toCross_position + toCross_height) {
jQuery("#logo img").css({filter : "invert(100%)"});
} else {
jQuery("#logo img").css({filter : "invert(0%)"});
}
}
);
Any help appreciated. Thanks!
you need to fire a div scroll event. you can assign
$("div1").scroll(function(){
//change the color of the div1
}
});
$("div2").scroll(function(){
//change the color of the div2
}
});
or you can assign a class to divs which you want to change the color
$(".div").scroll(function(){
//change the color of the div which you are scrolling now
}
});
You can use like this :-
$(window).scroll(function() {
var that = $(this);
$('.section').each(function() {
var s = $(this);
if (that.scrollTop() >= s.position().top) {
if(s.hasClass('active')) {
$('.logo').addClass('invert');
} else {
$('.logo').removeClass('invert');
}
}
});
});
body {
padding: 0;
margin: 0;
}
div {
background: #f00;
height: 400px;
}
.logo {
position: fixed;
top: 0;
left: 0;
width: 100px;
}
.logo.invert {
filter: invert(100%);
}
div:nth-child(even) {
background: #ff0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img src="https://dd.mintfresh.co.uk/wp-content/uploads/2018/06/DD_logo.svg" class="logo" />
<div id="page1" class="section"></div>
<div id="page2" class="section active"></div>
<div id="page3" class="section"></div>
<div id="page4" class="section active"></div>
<div id="page5" class="section"></div>
As your site code you can do like this :
$(window).scroll(function() {
var that = $(this);
$('#content > section').each(function() {
var s = $(this);
if (that.scrollTop() >= s.position().top) {
if(s.hasClass('black')) {
$('#logo img').css({filter: 'invert(0%)'});
} else {
$('#logo img').css({filter: 'invert(100%)'});
}
}
});
});

How to open a box on screen by clicking a link and hide it when clicked outside in JS

My goal is to have #box2 appear when I click on #box1 but when you click on something other than #box2, it will display none and only #box1 will show.
Here are my 2 boxes, they are just 2 styled divs:
var condition;
$(document).click(function() {
if (condition === 'block') {
$(":not(#box2)").click(function() {
$("#box2").hide();
});
}
})
$('#box1').click(function(e) {
$('#box2').css('display', 'block');
condition = 'block';
});
$('#box2').click(function(e) {
$('#box2').css('display', 'none');
condition = 'none';
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="box1" style="width: 300px; height: 300px; background-color: red; margin-left: 100px; margin-bottom: 50px; position: absolute;">
</div>
<div id="box2" style="width: 300px; height: 300px; background-color: blue; margin-left: 150px; display: none; position: absolute;">
</div>
This current code works correctly the first time but after that, it wont run again. I am just wondering if there is a reset function or where I am going wrong?
Really what I want to do is make this work on an ipad so when the user clicks/taps away from the box, it will close. If there are better ways to do this on the Ipad tablet, please let me know!!
Any ideas?
Don't overcomplicate things. This is all the javascript you need, get rid of everything else:
$(document).click(function () {
$('#box2').hide();
});
$('#box1').click(function (e) {
e.stopPropagation();
$('#box2').show();
});
You could just filter event target at document level:
$(document).on('click', function(e) {
$('#box2').toggle(!!$(e.target).closest('#box1').length);
});
-jsFiddle-
You can listen to all click events of the document and then use the event.target to detect which element is being clicked. if the clicked element is box1 and box2 is not being shown then display it to the user. in any other condition we can hide the box2 if it's not the element being clicked. here is the vanilla JavaScript code to achieve this:
<html>
<body>
<div id='box1'>BOX ONE</div>
<div id='box2' style="display: none;">BOX TWO</div>
<script>
document.addEventListener('click', function(event) {
var secondBox = document.getElementById('box2')
if(event.target.id === 'box1' && secondBox.style.display === 'none'){
secondBox.style.display = 'block'
} else if (event.target.id !== 'box2') {
secondBox.style.display = 'none'
}
})
</script>
</body>
</html>
And if you are into DRY (Do not repeat yourself), you can define a function for this task. Take look at this modified version of the script:
function addOpenHandler(handler, target){
document.addEventListener('click', function(event) {
if(event.target === handler && target.style.display === 'none'){
target.style.display = 'block'
} else if (event.target !== target) {
target.style.display = 'none'
}
})
}
addOpenHandler( document.getElementById('box1'), document.getElementById('box2') )
$(document).click(function () {
if (condition === 'block')
{
$(":not(#box2)").click(function () {
$("#box2").hide();
});
}
})
The line $("#box2").hide(); is firing after every click

Creating popup boxes using html css and javascript

basically i'm trying to create multiple popup boxes that appear when different links are clicked. For some reason, a popup box only appears when the first link is clicked. When the rest of the links are clicked, nothing happens. Any help is appreciated, thanks. Also, I've only included 2 of the links in this example.
javascript code:
function xpopup() {
document.getElementById("x").onclick= function(){
var overlay = document.getElementById("overLay");
var popup = document.getElementById("xPopup");
overlay.style.display = "block";
popup.style.display = "block";
}
}
function ypopup() {
document.getElementById("y").onclick= function(){
var overlay = document.getElementById("overLay");
var popup = document.getElementById("yPopup");
overlay.style.display = "block";
popup1.style.display = "block";
}
}
</script>
HTML code:
<body onLoad="xpopup()"; "ypopup()";>
<div id="overLay"></div>
<div class="popupBox" id="xPopup"></div>
<div class="popupBox" id="yPopup"></div>
Link 1<br>
Link 2<br>
CSS code:
.popupBox{
display:none;
position: fixed;
width: 30%;
height: 40%;
margin-left: 16.5%;
margin-top: 4.5%;
background-color: white;
border: 2px solid black;
border-radius: 10px;
z-index: 10;
}
#overLay{
display:none;
position: fixed;
width: 100%;
height: 100%;
background-color: #707070;
opacity: 0.7;
z-index: 9;
left: 0;
top: 0;
}
Replace <body onLoad="xpopup()"; "ypopup()";> with <body onLoad="xpopup(); ypopup();"> and in your JavaScript code you have a typo.
function ypopup() {
document.getElementById("y").onclick= function(){
var overlay = document.getElementById("overLay");
var popup = document.getElementById("yPopup");
overlay.style.display = "block";
popup1.style.display = "block"; // Here the popup1 is undefined change it to popup.style.....
}
}
Edit :-->
I've changed your code to hide the popup, if you click on the greyed out section.
Fiddle
HTML:
<body>
<div id="overLay"></div>
<div class="popupBox" id="xPopup"></div>
<div class="popupBox" id="yPopup"></div>
Link 1
<br />
Link 2
<br />
</body>
JavaScript:
var overlay = document.getElementById("overLay");
var xpopup = document.getElementById("xPopup");
var ypopup = document.getElementById("yPopup");
document.getElementById("x").onclick = function () {
overlay.style.display = "block";
xpopup.style.display = "block";
};
document.getElementById("y").onclick = function () {
overlay.style.display = "block";
ypopup.style.display = "block";
};
overlay.onclick = function () {
overlay.style.display = "none";
xpopup.style.display = "none";
ypopup.style.display = "none";
};
I'm seeing two issues --
The first is already answered by chipChocolate.py:
Replace <body onLoad="xpopup()"; "ypopup()";> with <body onLoad="xpopup(); ypopup();">.
The second (and maybe this is just a typo?) is that you have:
function ypopup() {
document.getElementById("y").onclick= function()
var overlay = document.getElementById("overLay");
var popup = document.getElementById("yPopup");
overlay.style.display = "block";
popup1.style.display = "block";
}
}
You're referencing popup1 but you've named your variable popup. If you open up the javascript console you'll probably see that's throwing an error. Rename the variable popup1 and this should work.

Categories

Resources