Dealing with click event handler on inner div and outer div - javascript

I've got modal window: parent div (wrapper with dark transparent background) and child div (with buttons, inputs and text). Both of them are fixed positioning.
In JavaScript I do simple code: If I click on parent fixed div (.modal-wrapper) - it must close (remove) whole modal window. And same result if I click on close button ('X' button in the corner of modal window).
Here is my simple JS code:
function doModalClose() {
modalWrapper.remove();
}
closeBtn.addEventListener('click', doModalClose);
modalWrapper.addEventListener('click', doModalClose);
And html markup:
<div class="modal-wrapper">
<div class="modal-window">
<div class="btn-wrapper"><span class="close-btn"></span></div>
other modal elements...
</div>
</div>
The main question is that when I click on parent div it works correctly, and as when I click on .close-btn. But if I clicked on child div (.modal-window) it closes whole modal too, which incorrect!
I make a simple alert(); check: when I click on parent one it should say Modal Wrapper and when I click on child one it should say Modal Window.
And when I click on child window it calls two alert(); functions: first is child's Modal Window and after that parent's Modal Wrapper.
So that's the reason of my issue, but I don't understand the reason of that kind of behavior. I use on child div z-index: 2; and z-index: 1; on parent div, but it still doesn't help.
Thank you for your attention!

This happens because one is inside another one, if you click the inner div you also click the outer one because the inner is inside the outer one. You need an extra handler just for .modal-window and to use event.stopPropagation(). Run this code snippet and see by yourself.
function doModalClose() {
modalWrapper.remove();
}
var closeBtn = document.getElementsByClassName('close-btn')[0]
var modalWrapper = document.getElementsByClassName('modal-wrapper')[0]
var modalWindow = document.getElementsByClassName('modal-window')[0]
var button1 = document.getElementsByClassName('button1')[0]
var button2 = document.getElementsByClassName('button2')[0]
closeBtn.addEventListener('click', doModalClose);
modalWrapper.addEventListener('click', doModalClose);
modalWindow.addEventListener('click', function (event) {
event.stopPropagation()
})
button1.addEventListener('click', function (event) {
alert('button1')
})
button2.addEventListener('click', function (event) {
alert('button2')
})
div {margin: 5px; padding: 5px}
.modal-wrapper {border: 2px solid red}
.modal-window {border: 2px solid blue}
.btn-wrapper, .btn {border: 2px solid green}
<div class="modal-wrapper">modal-wrapper
<div class="modal-window">modal-window
<div class="btn-wrapper"><span class="close-btn">button</span></div>
<a class="btn button1">Button1</a>
<a class="btn button2">Button2</a>
</div>
</div>

Related

How to trigger function only in parent div, not child

<button onClick={onClickParent}>
<div className={"iconDiv"}>
<div className={"iconNameDiv"}>
</button>
I have something like this structure.
When I click the button, It will change the color of the button
However, when I click the inside div, this onclick funtion didn't work.
How to prevent onclick inside div ? only parent
Generally whatever is inside a button tag should be used for the button click, so I would go for a div tag which can be used for alignment of children. Below is the code for preventing child element triggering clicks, just check the class and ensure that its the same as class of the parent div.
function test(event) {
if(event.target.className === 'test') {
console.log('execute click code');
}
}
.test {
padding: 50px;
}
<div onClick="test(event)" class="test">
<div className="test1"> asdfasdf</div>
<div className="test2"> asdfasdf</div>
</div>

How can i make a button clicked when i just click a div

<div id="mydiv"><div>
<button style="visibility:hidden; float:left"></button>
I wanna make the hidden button as is clicked when someone click the div "mydiv".
As AndrewL said, you don't need a button for this. But if you want to use a button anyways, simply assign a eventListener to your div that simulates a click on the button:
document.querySelector('#mydiv').addEventListener('click', () => {
document.querySelector('button').click();
});
Example
(I added some CSS rules and an extra function for visualization.)
document.querySelector('#mydiv').addEventListener('click', () => { // Listen for clicks on the div
document.querySelector('button').click(); // Simulate a click on the button
});
function test() { // This function gets called when clicking the button
console.log("Click!");
}
<div id="mydiv" style="height: 100px; width: 100px; background-color: red;">
<div>
<button style=" visibility:hidden; float:left; " onclick="test()"></button>
</div>
</div>
You dont need a hidden button for this. Just assign a click listener to the div itself using js like this:
const btn = document.getElementById('mydiv');
function doSomething(){
//run your script here when div is clicked
}
btn.addEventListener('click', doSomething);
You don't really need the hidden button to catch the click event. But if you really need it:
<div id="mydiv" onclick="document.getElementById('btn').click()">click on me<div>
<button id="btn" style="display:none;" ></button>
With jQuery, you can do something like this:
$('#div_id').click(function(){$('#btn_id').trigger('click');});
$('#btn_id').click(function(){//Business logic here on btn click
});

How to close a native HTML dialog when clicking outside with JavaScript?

I use an HTML <dialog> element. I want to be able to close the dialog when clicking outside of it.
Using "blur" or "focusout" event does not work.
I want the same thing as Material Design dialog, where it closes the dialog when you click outside of it:
https://material-components-web.appspot.com/dialog.html
How can I achieve that?
Thanks in advance.
When a dialog is opened in modal mode, a click anywhere on the viewport will be recorded as a click on that dialog.
The showModal() method of the HTMLDialogElement interface displays the dialog as a modal, over the top of any other dialogs that might be present. It displays into the top layer, along with a ::backdrop pseudo-element. Interaction outside the dialog is blocked and the content outside it is rendered inert.
Source: HTMLDialogElement.showModal()
One way to solve the question is to:
Nest a div inside your dialog and, using CSS, make sure it covers the same area as the dialog (note that browsers apply default styles to dialogs such as padding)
Add an event listener to close the dialog when a user clicks on the dialog element (anywhere on the viewport)
Add an event listener to prevent propagation of clicks on the div nested inside the dialog (so that the dialog does not get closed if a user clicks on it)
You can test this with the code snippet below.
const myButton = document.getElementById('myButton');
myButton.addEventListener('click', () => myDialog.showModal());
const myDialog = document.getElementById('myDialog');
myDialog.addEventListener('click', () => myDialog.close());
const myDiv = document.getElementById('myDiv');
myDiv.addEventListener('click', (event) => event.stopPropagation());
#myDialog {
width: 200px;
height: 100px;
padding: 0;
}
#myDiv {
width: 100%;
height: 100%;
padding: 1rem;
}
<button id="myButton">Open dialog</button>
<dialog id="myDialog">
<div id="myDiv">
Click me and I'll stay...
</div>
</dialog>
This is how I did it:
function dialogClickHandler(e) {
if (e.target.tagName !== 'DIALOG') //This prevents issues with forms
return;
const rect = e.target.getBoundingClientRect();
const clickedInDialog = (
rect.top <= e.clientY &&
e.clientY <= rect.top + rect.height &&
rect.left <= e.clientX &&
e.clientX <= rect.left + rect.width
);
if (clickedInDialog === false)
e.target.close();
}
Modal
To close a modal dialog (i.e. a dialog opened with showModal) by clicking on the backdrop, you could do as follows:
const button = document.getElementById('my-button');
const dialog = document.getElementById('my-dialog');
button.addEventListener('click', () => {dialog.showModal();});
// here's the closing part:
dialog.addEventListener('click', (event) => {
if (event.target.id !== 'my-div') {
dialog.close();
}
});
#my-dialog {padding: 0;}
#my-div {padding: 16px;}
<button id="my-button">open dialog</button>
<dialog id="my-dialog">
<div id="my-div">click outside to close</div>
</dialog>
This places the dialog content in a <div>, which is then used to detect whether the click was outside the dialog, as suggested here. The padding and margins in the example are adjusted to make sure the <dialog> border and <div> border coincide.
Note that the modal dialog's "background" can be selected in CSS using ::backdrop.
Non-modal
For a non-modal dialog (opened using show), you could add the event listener to the window element instead of the dialog, e.g.:
window.addEventListener('click', (event) => {
if (!['my-button', 'my-div'].includes(event.target.id)) {
dialog.close();
}
});
In this case we also need to filter out button clicks, otherwise the dialog is immediately closed after clicking the "open dialog" button.
Well, code it the same way you speak it.
If you click on an element that isn't the desired dialog, close the dialog.
Here is an example:
<div id="content">
<div id="dialog" class="dialogComponent">
<div id="foo" class="dialogComponent">
test 123 123 123 123
<input class="dialogComponent class2" type="text">
</div>
<button class="dialogComponent">Submit</button>
</div>
</div>
#content { width: 100%; height: 333px; background-color: black;}
#dialog { margin: 33px; background-color: blue; }
$('#content').click(function(e) {
if (!e.target.classList.contains("dialogComponent"))
alert('Closing Dialog');
});
https://jsfiddle.net/scd9mwk7/

Stop propogation of event listener click but still allow other click events to occur within the element

I have created a fairly classic modal. Fixed modal in the middle of the screen. Semi-transparent background and a box in the middle.
The box contains some click event listeners (e.g a close X and a button that performs another action).
I want to allow the user to close the modal by clicking on the outer background.
HTML example
<div class="modal">
<div class="modal__inner">
<div class="modal_closebtn">X</div>
</div>
</div>
Currently, I have the following to handle closing the modal based on click of .modal, which covers the whole screen.
document.querySelector(".modal").addEventListener("click", () => {
this.toggleModal();
});
My problem is, this fires if you click inside the .modal__inner too.
So I tried adding an eventListener to stopPropagation()
document.querySelector(".modal__inner").addEventListener("click", e => {
e.stopPropagation();
});
This now blocks the eventListener for my .modal_closebtn and any other events that occur inside the modal.
How can I ensure that the click for the background div only works on the modal div not modal__inner or any others? Unfortunately when I review e.currentTarget after clicking inside my div it returns .modal not .modal__inner even though it does appear that I clicked inside that div.
Non jQuery solution please
To avoid the execution of querySelector too many times and gain a little of performance, store that result into a variable.
var elem = document.querySelector(".modal")
elem.addEventListener("click", (e) => {
if (e.target !== elem) return;
console.log('toggle!');
//this.toggleModal();
});
.modal {
width: 300px
height: 300px;
border: 1px solid #000
}
.modal__inner {
width: 100px
height: 100px;
border: 1px solid red
}
<div id="hola" class="modal">
Parent modal
<br>
<br>
<br>
<div id="epale" class="modal__inner">
Inner modal
<div class="modal_closebtn">X</div>
</div>
</div>
Happy coding!
The event object has the original target of the event, use that to figure out what is the source of the event.
var modal = document.querySelector(".modal");
modal.addEventListener("click", (e) => {
if (e.target !== modal) return;
this.toggleModal();
});

Button remains active when re-added to DOM

I've been experiencing a really bizarre issue with IE9 and IE10 (Win7 only).
If an HTML element (button, span, anchor) has an attached click listener which removes itself (or it's container) from the DOM--and then at a later point some other event (e.g: reset) adds the element back, the element still remains in ':hover' state, even without the mouse hovering on the element.
WHY does IE 9 & IE10 (Win7) do this? Also, is there a workaround, without resorting to some setTimeout async call?
Take a look at this JSBin: IE hover/active on remove/add
Code from JSBin
<div id="outer" style="border: 2px solid green; padding: 10px;">
<div id="container" style="border: 2px solid black; padding: 5px;">
<button id="button">Hide Me</button>
</div>
</div>
<button id="reset" style="margin-top: 20px">Reset</button>
And the JS:
var outer = document.getElementById('outer');
var container = document.getElementById('container');
var button = document.getElementById('button');
button.addEventListener('click', function() {
outer.removeChild(container);
}, false);
var reset = document.getElementById('reset');
reset.addEventListener('click', function() {
outer.appendChild(container);
}, false);
I'm leaning towards this being a bug in IE were if the element is removed from the DOM the styles aren't being refreshed correctly. However it seems that if you remove the container div as per below the :hover issue is fixed in IE.
I know you said without the use of setTimeout, but I haven't been able to make something else work.
button.addEventListener('click', function() {
window.setTimeout(function() {
outer.removeChild(container);
}, 1);
}, false);

Categories

Resources