I have 2 containers, one on top of the other, being controlled by zIndex whether event is mouseover/mouseout;
There is an issue with event bubbling whereby the child element fires off the parent event. I could change the event to mouseleave from mouseout which resolves the issue but how would I go about then changing the zIndex of the target element?
giphyContainer.addEventListener('mouseover', (e) => {
let backPanel = e.target.parentElement.querySelector('.giphyImg__Back');
let frontPanel = e.target.parentElement.querySelector('.giphyImg__Front');
let target = e.target;
if (target.className === "giphyImg__Front") {
frontPanel.style.zIndex = "-3";
backPanel.style.zIndex = "3";
}
});
giphyContainer.addEventListener('mouseleave', (e) => {
// Previously worked with event of mouseout
// let backPanel = e.target.parentElement.querySelector('.giphyImg__Back');
// let frontPanel = e.target.parentElement.querySelector('.giphyImg__Front');
// console.log(backPanel);
// e.target - event that troggered the event
// e.currentTarget - the event listener element
console.log(e);
let backPanel2 = e.target.firstChild.lastElementChild;
let frontPanel2 = e.target.firstChild.firstElementChild;
console.log(backPanel2);
console.log(frontPanel2);
if (backPanel2.className === "giphyImg__Back") {
frontPanel2.style.zIndex = 3;
backPanel2.style.zIndex = -3;
}
});
You can stop the event from bubbling on to the parent by using event.stopPropagation() on your child elements.
child.addEventListener('mouseout',(event) => {
event.stopPropagation();
})
Related
I have a function that makes an element from a list of elements change its .className when clicked, so lets say when I click the element becomes one color and the others another color. This function is the following:
const memberB = document.querySelectorAll('#memberBoxAlex,
#memberBoxLiv, #memberBoxFlo');
for (let i = 0; i < memberB.length; i++)
memberB[i].onclick = function(){
memberBoxAlex.className = "faded";
memberBoxLiv.className = "faded";
memberBoxFlo.className = "faded";
if(memberB[i].className=="open"){
memberB[i].className="";
}
else{
memberB[i].className="open";
}
This works perfectly, but what I want to happen next, is when I click outside its box to stop the all the effects so to make all memberB "normal" let's say, so to have .className="". I've tried to give to their container this function:
let exitEffect = document.getElementById(team)
exitEffect.onclick = function(){
memberBoxAlex.className = "";
memberBoxLiv.className = "";
memberBoxFlo.className = "";}
How can I do so when I click outside the box of the member all className for memberB will "stop" or become .className="".
use a single class for this for a more generic selector and I use this snippet to use a single event listener for this.
window.addEvent = (event_type, target, callback) => {
document.addEventListener(event_type, function (event) {
// If the event doesn't have a target
// Or the target doesn't look like a DOM element (no matches method
// Bail from the listener
if (event.target && typeof (event.target.matches) === 'function') {
if (!event.target.matches(target)) {
// If the element triggering the event is contained in the selector
// Copy the event and trigger it on the right target (keep original in case)
if (event.target.closest(target)) {
const new_event = new CustomEvent(event.type, event);
new_event.data = { originalTarget: event.target };
event.target.closest(target).dispatchEvent(new_event);
}
} else {
callback(event);
}
}
});
};
and then
window.addEvent('click', '.openable-member', (event) => {
document.querySelectorAll('.openable-member').each((element) => {
if (element !== event.target) {
element.classList.add('faded');
element.classList.remove('open'); // guessing you'll need this too
}
});
event.target.classList.toggle('open');
});
The Document method querySelectorAll() returns a static (not live) NodeList representing a list of the document's elements that match the specified group of selectors.
So you can map through memberB because it's not an array.
What you can do is:
const memberB = document.querySelectorAll('#memberA,#memberAA, #memberAAA ');
memberB.onclick = function(){
memberB.className = "faded";
if(memberB.className == "open"){
memberB.className = "";
}
else{
memberB.className = "open";
}
}
You can try this:
memberB[i].className = memberB[i].className.replace("open", "");
This code adds a mouseover eventListener to the parent of the element:
const el = this.$refs.tooltip
el.parentElement.addEventListener('mouseover', () => {
el.style.display = 'block'
setTimeout(() => {
el.style.display = 'none'
}, 500)
})
However, the tooltip disappears even when the cursor stays on the parent.
How to keep the tooltip displaying and only make it disappear when the cursor leaves the element's parent?
var parent = el.parentElement;
parent.addEventListener("mouseover",() => {el.style.display = 'block'});
parent.addEventListener("mouseout",() => {el.style.display = 'none'});
// take care of parent dom structure because mouseout will fire from any children
// take care of ()=>{... this ...} syntax because will not bind 'this' to parent while function(ev){... this ...} does
I have circle menu with rotation. And after simple click i want to fire click event, but during rotation - mousemove i want ignore click. For now i have -
<g id="bottomMenuRotate" onMouseDown={this.selectElement.bind(this)}>
Then my select function looks -
selectElement(e){
let groupRotate = document.getElementById('bottomMenuRotate');
groupRotate.onmousemove = function(e) {....}
groupRotate.onmouseup = function(e){
groupRotate.onmousemove = null;
}
}
So how i cant prevent click? I tried something like
groupRotate.onmouseup = function(e){
e.stopPropagation();
groupRotate.onmousemove = null;
};
or
groupRotate.onmouseclick = function(e){
e.stopPropagation();
}
but this prevents every click. Any tips how i can do it?
So i finally found simply solution
selectElement(e){
let move = false;
groupRotate.onmousemove = function(e) {
move = true;
}
groupRotate.onclick = function(e){
move ? e.preventDefault() : false;
}
}
This prevent click only when move is set to true.
Set a state in your onMouseMove handler that prevents the click events from running:
groupRotate.onmousemove = (e) => {
this.setState({ mouseMoving: true });
}
groupRotate.onmouseup = (e) => {
this.setState({ mouseMoving: false });
}
Somewhere else:
groupRotate.onmouseclick = (e) => {
if (!this.state.mouseMoving) {
...
};
}
Note the arrow functions to make this available within the functions.
I am using the following code to create a popup bubble when a user double-clicks on the webpage:
function displaySomething(x, y) {
var div = document.createElement("div");
div.id = "displaySomething_div";
....
}
var listener = function (event) {
if (event.button == 0 ) {
var div = document.getElementById("displaySomething_div");
if (div) {
document.body.removeChild(div);
}
displaySomething(event.pageX, event.pageY);
}
};
document.addEventListener("dblclick", listener, false);
Currently, the popup bubble will only be dismissed when I double-click on the page or on the bubble.
Is it possible to dismiss the popup bubble only when a single-click over non-bubble area of the page is made? That is, if I click or select over the bubble, the bubble will stay there.
Add a click handler to the popup div which stops propagation of the click event, and then you can safely attach a click handler to the document parent.
Example: http://jsfiddle.net/M6asx/
function displaySomething(x, y) {
var div = document.createElement("div");
div.id = "displaySomething_div";
...
div.addEventListener('click', function(e) { e.stopPropagation(); }, false);
}
var listener = function (event) {
if (event.button == 0) {
var div = document.getElementById("displaySomething_div");
if (div) {
document.body.removeChild(div);
} else {
displaySomething(event.pageX, event.pageY);
}
}
};
document.addEventListener('click', listener, false);
I need to capture an event instead of letting it bubble. This is what I want:
<body>
<div>
</div>
</body>
From this sample code I have a click event bounded on the div and the body. I want the body event to be called first. How do I go about this?
Use event capturing instead:-
$("body").get(0).addEventListener("click", function(){}, true);
Check the last argument to "addEventListener" by default it is false and is in event bubbling mode. If set to true will work as capturing event.
For cross browser implementation.
var bodyEle = $("body").get(0);
if(bodyEle.addEventListener){
bodyEle.addEventListener("click", function(){}, true);
}else if(bodyEle.attachEvent){
document.attachEvent("onclick", function(){
var event = window.event;
});
}
IE8 and prior by default use event bubbling. So I attached the event on document instead of body, so you need to use event object to get the target object. For IE you need to be very tricky.
I'd do it like this:
$("body").click(function (event) {
// Do body action
var target = $(event.target);
if (target.is($("#myDiv"))) {
// Do div action
}
});
More generally than #pvnarula's answer:
var global_handler = function(name, handler) {
var bodyEle = $("body").get(0);
if(bodyEle.addEventListener) {
bodyEle.addEventListener(name, handler, true);
} else if(bodyEle.attachEvent) {
handler = function(){
var event = window.event;
handler(event)
};
document.attachEvent("on" + name, handler)
}
return handler
}
var global_handler_off = function(name, handler) {
var bodyEle = $("body").get(0);
if(bodyEle.removeEventListener) {
bodyEle.removeEventListener(name, handler, true);
} else if(bodyEle.detachEvent) {
document.detachEvent("on" + name, handler);
}
}
Then to use:
shield_handler = global_handler("click", function(ev) {
console.log("poof")
})
// disable
global_handler_off("click", shield_handler)
shield_handler = null;