Japascript Close modal when user click outside the modal - javascript

I have this simple code
const readmore = document.getElementById("read");
const modaloverlay = document.getElementById("modaloverlay");
const closeButton = document.querySelector(".closebutton");
readmore.addEventListener("click", function () {
modaloverlay.classList.add("overlayshows");
});
closeButton.addEventListener("click", function () {
modaloverlay.classList.remove("overlayshows");
});
window.addEventListener('click', function(e){
if ((modaloverlay.classList.contains("overlayshows")) && (e.target != modaloverlay)) {
modaloverlay.classList.remove("overlayshows");
}
});
.overlay {
background: rgba(0,0,0,.9);
padding: 20px;
position: fixed;
top: 10px;
bottom: 10px;
left: 0;
right: 0;
align-items: center;
justify-content: center;
display: none;
max-width: 600px;
margin: 0 auto;
color: #fff
}
.overlayshows {
display: block;
}
.closebutton {
cursor: pointer;
float: right;
}
<div class="modal">
<h1>Content</h1>
<button id="read">READ MORE</button>
</div>
<div class="overlay" id="modaloverlay">
<span class="closebutton">X</span>
<div class="modalinfo" >
Morecontent
</div>
</div>
When i click the button the modal is opened, this part is easy; i know that if i remove the last part of js it will work, but i want that if you click out the modal, the modal is closed, i dont know what is wrong.
Thanks :)

This solution creates a modal singleton to make it easier to manage the lifecycle of the component. It also uses event delegation for easy event management. The key problem with your solution was not preventing the modal click event from propagating.
const modal = {
CLASSES: {
SHOW: 'overlayshows',
CLOSE_BUTTON: 'closebutton',
MODAL: 'modaloverlay',
READ: 'read'
},
isVisible: false,
el: document.getElementById("modaloverlay"),
initialize() {
modal.addEvents();
},
show() {
modal.el.classList.add(modal.CLASSES.SHOW);
modal.isVisible = true;
},
hide() {
modal.el.classList.remove(modal.CLASSES.SHOW);
modal.isVisible = false;
},
addEvents() {
modal.removeEvents();
modal.el.addEventListener('click', modal.eventHandlers.onModalClick);
window.addEventListener('click', modal.eventHandlers.onWindowClick);
},
removeEvents() {
modal.el.removeEventListener('click', modal.eventHandlers.onModalClick);
window.removeEventListener('click', modal.eventHandlers.onWindowClick);
},
eventHandlers: {
onModalClick(event) {
event.stopImmediatePropagation();
if (!event.target) {
return;
}
if (event.target.classList.contains(modal.CLASSES.CLOSE_BUTTON)) {
modal.hide();
}
},
onWindowClick(event) {
if (event.target.classList.contains(modal.CLASSES.READ)) {
modal.show();
} else {
modal.hide();
}
}
}
}
modal.initialize();

W3schools has a good tutorial on modals: https://www.w3schools.com/howto/howto_css_modals.asp
The code is as follows for closing a modal if a user clicks outside of it:
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}

Related

hide button onmouseenter isn't triggering

My onmouseenter function isn't triggering.
I created a button that would allow you to go to the top. However, once there I want the button to have a display property of none. I tried doing it in two ways. One with classList and the other with style.display = 'none'. Both didn't work, am I missing something in the logic ?
EDIT-------------
onmouseleave the button should reappear. I added the function.
Here is a code pen
const topDiv = document.getElementById('topDiv')
const arrowup = document.getElementById('arrowup')
const hideArrow = () => {
if (topDiv) {
arrowup.classList.remove(showme');
arrowup.classlist.add('hideme');
} else {
arrowup.classList.add('showme');
}
}
const showArrow = () => {
if (!topDiv) {
arrowup.classList.remove('hideme');
arrowup.classList.add('showme');
}
}
#top {
height: 1000px;
}
a {
position: fixed;
top: 10px;
}
.showme {
display: block;
}
.hideme {
display: none;
}
<div onmouseleave="showArrow() onmouseenter="hideArrow()" id="top">
hello
</div>
<a class="showme" id="arrowup" onClick="hideArrow()" href="#top">
click me
</a>
There are some issues:
onmouseenter="hideArrow" is missing brackets -> onmouseenter="hideArrow()"
add and remove are functions, that get the class as param -> add('showme')
the return is wrong -> remove it
Working example:
const topDiv = document.getElementById('topDiv')
const arrowup = document.getElementById('arrowup')
const hideArrow = () => {
if (topDiv) {
arrowup.classList.remove('showme');
arrowup.classList.add('hideme');
}
else {
arrowup.classList.add('showme');
}
}
#top {
height: 1000px;
}
a {
position: fixed;
top: 50px;
}
.showme {
display: block;
}
.hideme {
display: none;
}
<div onmouseenter="hideArrow()" id="topDiv">
hello
</div>
<a class="showme" id="arrowup" onClick="hideArrow()" href="#topDiv">
click me
</a>
Remove the return keyword from the if condition because it causes the function to stop running at that point
element.classList.add() is a function while you are assigning classes to the element using the '=' operator. So the correct way to do it is arrowup.classList.add('hideme') and arrowup.classList.remove('showme').

Hide an expanded menu when clicking outside of the container: how to use code snipet

I have a menu that open a sub-menu section onclick (let's name the container: "sub-menu").
I would like "sub-menu" to disapear if the user click outside of it / on the rest of the page.
It seems to be solved on How do I detect a click outside an element?
But I can't get how to use the code snipet from the second most popular answer:
export function hideOnClickOutside(selector) {
const outsideClickListener = (event) => {
const $target = $(event.target);
if (!$target.closest(selector).length && $(selector).is(':visible')) {
$(selector).hide();
removeClickListener();
}
}
const removeClickListener = () => {
document.removeEventListener('click', outsideClickListener)
}
document.addEventListener('click', outsideClickListener)
}
Could you please guide me on how to use it?
I edited, and included a basic example. -> I want sub menu to also close when clicking on the "white" space. But not on the parent "main menu" element.
document.getElementById("main-menu").addEventListener("click", function() {bouttonexpand('sub-menu-class')});
function bouttonexpand(id) {
var elemeacacher = document.getElementsByClassName(id);
if (elemeacacher[0].style.display != "none"){
for(var y=0;y<elemeacacher.length;y++)
elemeacacher[y].style.display = "none";
}
else {
for(var y=0;y<elemeacacher.length;y++)
elemeacacher[y].style.display = "block";
}
}
#main-menu {
display:inline-block;
height:20px;
width:100px;
background: blue;
padding: 5%;
}
#sub-menu {
display:inline-block;
height:50px;
width:50px;
background: red;
display: none;
}
<div><div id="main-menu">Main menu</div></div>
<div><div id="sub-menu" class="sub-menu-class">Sub menu</div></div>
Thanks
By using jQuery, you can bind to the document click event and hides the div container when the clicked element isn’t the container itself or descendant of the div element.
var container = $("#sub-menu");
if (!container.is(event.target) && !container.has(event.target).length) {
container.hide();
}
If you want to hide that container without being tested the container itself or descendant of the div element just remove the condition and simply use container.hide();.
Also, rather than setting display: none; on sub-menu in the CSS, set it manually so that you can toggle the sub-menu from the very first click.
Have a look at the snippet below:
var x = document.getElementById("sub-menu");
x.style.display = "none";
$(document).click(function (evt) {
if ($(evt.target).is('#main-menu')) { // control click event if it's main-menu
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
}
else {
var container = $("#sub-menu");
if (!container.is(event.target) && !container.has(event.target).length) { // if you don't want that remove the condition and write container.hide(); only
container.hide();
}
}
});
#main-menu {
display: inline-block;
height: 20px;
width: 100px;
background: blue;
padding: 5%;
}
#sub-menu {
display: inline-block;
height: 50px;
width: 50px;
background: red;
}
<script src="https://code.jquery.com/jquery-3.5.1.min.js"
integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<div id="main-menu">Main menu</div>
<div id="sub-menu" class="sub-menu-class">Sub menu</div>

Return scrollbar when user clicks outside of popup to close it

I have jQuery code that removes the scrollbar while the popup modal is open. So, when I need to close popup, the scrollbar needs to appear again and the function works as intended except for one thing: if the user clicks elsewhere outside of the popup it will close, but the scrollbar remains hidden. It only works fully as intended when the close icon is clicked.
Is there any possibility to set auto overflow scrolling when the user clicks outside of the popup box? i.e. Not just on the close icon?
$(document).ready(function () {
$("button#mainbtn").click(function (){
$('body').css('overflow', 'hidden');
});
$(document).on('click', '.closer', function (){
$('body').css('overflow', 'auto');
});
});
<div id="myModal" class="modal" >
<div class="modal-content">
<div class="closer">×</div>
</div>
</div>
Code that opens modal box:
var modal = document.getElementById('myModal');
var btn = document.getElementById("mainbtn");
var span = document.getElementsByClassName("closer")[0];
btn.onclick = function() {
modal.style.display = "block";
}
span.onclick = function() {
modal.style.display = "none";
}
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
css:
.modal {
display: none;
z-index: 100;
padding-top: 100px;
position:fixed;
top: 0;
width: 100%;
height: 100%;
}
.modal-content {
background-color: #f2f2f2;
margin: auto;
position:relative;
width: 60%;
height:90%;
transition: all 5s ease-in-out;
}
.closer {
top:0px;
right:20px;
color: #00284d;
position:absolute;
font-size: 45px;
}
As you have attached an event to close the modal, if they click outside of it you can set the overflow to auto just after you hide the modal.
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
$('body').css('overflow', 'auto');
}
}
you can make a $("html").click(function() and check if your popup is visible or hidden. The function is executed every time a click is made on the entire page
$("html").click(function() {
if($('.popup').is(":visible")){
alert("visible: dont show scroll")
}
else{
alert("hidden: show scroll")
}
});
$("button").click(function() {
$('.popup').toggle();
});
body{
background-color: blue;
height; 1000px;
width: 1000px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div class="popup">popup</div>
<button>toggle popup</button>
</body>

Handle dropdown's focus state

I am currently making a dropdown component in pure JavaScript. When the user click on the dropdown toggle, the content gain focus and its content is being displayed. When the user click outside of it, then the content loses its focus and it gets hidden.
So far, it works great. However, I am encountering two problems.
The first one is that when an element inside the dropdown is clicked (eg: anchor tags), the dropdown loses focus, which it shouldn't.
The second one is that when the dropdown toggle is clicked while the dropdown content is being displayed, the dropdown should close instead of closing then re-opening due to the click registered on the dropdown toggle.
HTML:
<div class="dropdown">
Dropdown toggle
<div class="dropdown-content" tabindex="0">
<ul>
<li>
My profile
</li>
<li>
Log out
</li>
</ul>
</div>
</div>
CSS:
.dropdown {
position: relative;
}
.dropdown.is-open .dropdown-content {
display: block;
}
.dropdown-content {
display: none;
position: absolute;
top: 100%;
width: 100%;
padding: 0.5rem 0;
background: #fff;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
}
JS:
class Dropdown {
constructor(element) {
this.element = element;
this.toggle = this.element.querySelector('.dropdown-toggle');
this.content = this.element.querySelector('.dropdown-content');
this.bindings();
}
bindings() {
this.toggle.addEventListener('click', this.open.bind(this));
this.content.addEventListener('keydown', this.handleKeyDown.bind(this));
this.content.addEventListener('focusout', this.close.bind(this));
}
open(e) {
e.preventDefault();
this.element.classList.add('is-open');
this.content.focus();
}
close(e) {
this.element.classList.remove('is-open');
}
handleKeyDown(e) {
if (e.keyCode === 27) {
this.close(e);
}
}
}
document.querySelectorAll('.dropdown').forEach(dropdown => new Dropdown(dropdown));
I have been trying to get my head around on how I would solve these issues without any luck. Any idea on how to solve these issues?
After some testing I found a solution that works. Try the code below
class Dropdown {
constructor(element) {
this.element = element;
this.toggle = this.element.querySelector('.dropdown-toggle');
this.content = this.element.querySelector('.dropdown-content');
this.bindings();
}
bindings() {
this.toggle.addEventListener('click', this.open.bind(this));
this.content.addEventListener('keydown', this.handleKeyDown.bind(this));
this.element.addEventListener('focusout', this.onFocusOut.bind(this),true);
}
onFocusOut(e) {
if (!this.element.contains(e.relatedTarget)) {
this.close(e)
}
}
open(e) {
e.preventDefault();
this.element.classList.toggle('is-open');
this.content.focus();
}
close(e) {
e.preventDefault();
this.element.classList.remove('is-open');
}
handleKeyDown(e) {
if (e.keyCode === 27) {
this.close(e);
}
}
}

How Can I Make Popup Blog Content in Wordpress

I want to display my reference works on index. I limited the words. My aim is this: User who wants to learn detail information about post, will click the post thumbnail and the rest of content will open with popup.
I used w3css modal to make it. My javascript codes are:
// Get the modal
var modal = document.getElementById('myModal');
// Get the button that opens the modal
var btn = document.getElementById("myBtn");
// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];
// When the user clicks on the button, open the modal
btn.onclick = function() {
modal.style.display = "block";
}
// When the user clicks on <span> (x), close the modal
span.onclick = function() {
modal.style.display = "none";
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
But only the first post seems like that. The others have no reaction.
Thanks.
I want to make all thumbnails like that
I made some revision about that. I used fancybox 2 and change my code with this
<?php the_post_thumbnail('thumbnail', array('class' => 'aligncenter')); ?>
<div id="inline1" style="width:400px;display: none;">
<?php the_post_thumbnail('thumbnail', array('class' => 'aligncenter')); ?><?php the_content(); ?>
</div>
Now all the thumbnails open with fancybox but this time the other thumbnails' contents are same with the first post.
I don't think create a modal element in every container is a right way to go.
Instead, I will suggest you make only one modal element, and change the content of
that modal when any image got clicked.
thus, here is a demo that I just made
JSbin
The step will be
find out all container elems
bind those elems with click event
when user click one elem, extract the text and image src of that elem
inject into modal-body
removve hide class
It's fine to have modals mixed in. You have to be a little picky about event handlers and which one to close, but it's not too bad.
var sites = document.querySelectorAll('.site');
var closes = document.querySelectorAll('.close');
var ix;
for (ix = 0; ix < sites.length; ix++) {
sites.item(ix).addEventListener('click', showModal);
}
for (ix = 0; ix < closes.length; ix++) {
closes.item(ix).addEventListener('click', closeModal);
}
function showModal(e) {
e.stopPropagation();
this.querySelector('.modal').style.display = "block";
}
function closeModal(e) {
e.stopPropagation();
try {
getParent(this, 'modal').style.display = "none";
} catch (e) {
console.warn('Failed to find my daddy.');
}
}
function getParent(el, cls) {
while (el.parentElement) {
el = el.parentElement;
if (el.classList.contains(cls)) return el;
}
return null;
}
.site {
display: inline-block;
}
.thumbnail {
width: 100px;
height: 100px;
border: 1px solid black;
margin: 10px;
}
.modal {
display: none;
position: fixed;
z-index: 1;
padding-top: 100px;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.4);
}
.modal-content {
background-color: #fefefe;
margin: auto;
padding: 20px;
border: 1px solid #888;
width: 50%;
}
.close {
color: #aaaaaa;
float: right;
font-size: 28px;
line-height: 28px;
font-weight: bold;
cursor: pointer;
}
.close:hover,
.close:focus {
color: #000;
}
<link href="//cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css" rel="stylesheet" />
<div class="container">
<div class="site">
<div class="thumbnail"></div>
<div class="modal">
<div class="modal-content">
<span class="close">×</span> First Item
</div>
</div>
</div>
<div class="site">
<div class="thumbnail"></div>
<div class="modal">
<div class="modal-content">
<span class="close">×</span> Second Item
</div>
</div>
</div>
</div>

Categories

Resources