I'm trying to create an overlay which has an outer div (half see-through) and above an smaller inner content div. Clicking on the outer area makes the overlay dissappear. Clicking on the content area should interact with the overlay content.
Looking at my example code, clicking on the red area first raises an alert "red" and afterwards an alert "black" thus closing the overlay immediatly after the first interaction.
How can I prevent the onclick event of the underlying black div to trigger when the above red div is clicked?
<div onclick = "window.alert('black')" style = "background-color:black; width:100%; height:100%">
<div onclick = "window.alert('red')" style = "background-color:red; position: absolute; top:10%; left:10%; width: 80%; height: 80%;">
some content
</div>
</div>
I couldn't find anything online about that except people setting pointer-events to none which would disable the user to interact with the overlay content.
Also setting different z-indeices didn't work either.
If you want to verify the clickthrough happening: https://onlinegdb.com/rJbOmB0FV
This is more of a javascript behaviour you're experiencing.
Bubbling
The bubbling principle is simple.
When an event happens on an element, it first runs the handlers on it, then on its parent, then all the way up on other ancestors.
Use event.stopPropagation()
Definition and Usage
The stopPropagation() method prevents propagation of the same event from being called.
Propagation means bubbling up to parent elements or capturing down to child elements.
https://www.w3schools.com/jsref/event_stoppropagation.asp
Update
A simple function will be easier to handle.
Something like this:
const alert = (text) => {
event.stopPropagation();
window.alert(text)
}
<div onclick = "alert('black')" style = "background-color:black; width:100%; height:100%">
<div onclick = "alert('red')" style = "background-color:red; position: absolute; top:10%; left:10%; width: 80%; height: 80%;">
some content
</div>
</div>
Related
Using the Google Chrome browser, I need to drag-and-drop an item from a menu, in a way so that the menu will automatically close/hide/collapse/disappear/(or something similar) as soon as the dragstart event fires. This has to be done in a way such that the DOM space is freed up, so approaches using "visibility" and "opacity" for instance while possible are not good for this situation.
Instead, it is necessary to do something like display:none or pushing the menu off of the web page (without scrollbar). However, I've gotten stuck trying to accomplish this and could use some help (or if an alternative approach comes to mind that accomplishes the same, please let me know. I also tried a z-index approach without success.):
Approach 1 - Trying to hide dragged item's parent element via absolute positioning
https://jsfiddle.net/gratiafide/4m5r186v/
function dragstart_handler(ev) {
ev.dataTransfer.setData("text/plain", ev.target.id);
ev.currentTarget.parentElement.style.cssText = "position:absolute; right:-5000px;";
}
Approach 2 - Trying to hide dragged item's parent via setting display:none
https://jsfiddle.net/gratiafide/Luj7d089/
function drag(event) {
event.dataTransfer.setData("Text", event.target.id);
document.getElementById('parent').style.display = 'none';
}
You will see in both approaches, the dragged item gets dropped in both instances as soon as the CSS rule gets applied to the dragged item's parent element. I just want to be able to keep dragging the element even though I've hidden or moved the parent element out of sight. Thanks in advance for your help!
You seem to want your parents to disappear by dragging your child's element as it is.
The child element is influenced by the CSS style attribute of the parent element. If parents are erased through css properties such as "display", "visibility", and "opacity", the child element is not visible unconditionally.
Hiding using the "absolute" property(but not z-index -1) is also a way, but unwanted scrollbars may occur depending on the "overflow" attribute of the parent element, and the child element position must be added in reverse and recalculated.
As a result of my test, a dragend event occurred in Chrome when the parent element of the element to be dragged was redrawn. But in Firefox, both of your examples work.
Anyway, to explain based on how it works in Chrome, it is to separate the relationship between Child and Parent and use it as a sibling. Modify your HTML as follows.
<div id='relative_div'>
<div id="parent"></div>
<p id="source" ondragstart="dragstart_handler(event);" draggable="true">Drag me to the Drop Zone below</p>
</div>
Next update your CSS as follows. #parent should serve as a background for filling in #relative_div.
#relative_div {
position: relative;
overflow: hidden;
width: 200px;
height: 100px;
padding: 2em;
}
#parent {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
background-color: lightgrey;
}
#source {
position: relative;
cursor: grab;
color: blue;
border: 1px solid black;
}
Now, regardless of whether you use #parent's "position" to push it away, or hide it using "display", "opaicty", or "visibility", #source drag does not stop.
ok, I think my comment was wrong and that you want to remove the space on the page occupied by the origin element (rather than freeing up memory).
To achieve this, add document.body.removeChild(document.getElementById('parent')); to your drop handler. I've made a js fiddle to demonstrate (with the id=spacer div removed and an extra paragraph below it to show the element is removed):
https://jsfiddle.net/dj825rbo/
(revision following comment clarifying that the origin element should disappear as the drag begins)
This is horrible, but works (horrible because you can't see the text while it is being dragged). It relies on a hidden element into which the origin's content is stored while the drag is proceeding. Replacing the 'drop' event listener with a 'mouseup' listeners, allows the content of the temp (hidden element to be transferred to the target where the mouse click was released)
https://jsfiddle.net/dj825rbo/1/
I'm trying to make a page with a background and a content div, one overlapping the other. The div with a class of "content" receives the hover event however the div with a class of "background" receives nothing. I'm not actively disrupting the event in js in any way.
.container {
height: 100%;
width: 100%;
opacity: 1;
}
.background {
height: 100%;
width: 100%;
position: absolute;
}
.content {
height: 100%;
width: 100%;
position: absolute;
}
<div class="container">
<div class="background" onmouseover="test(this)">
</div>
<div class="content">
<!-- PANELS -->
<div class="facePanel" onmouseover="hoveringFacePanel(this)" onmouseleave="hoveringFacePanelOff(this)">
<img class="imageShown" src="https://i.pinimg.com/736x/70/d4/22/70d422d5972596f603a94c0faf24a43d--advertising-design-advertising-campaign.jpg" />
<img src="https://apple.insidercdn.com/gallery/21413-24435-Screenshot_1-l.jpg" class="imageShown" />
</div>
<!-- PANELS -->
</div>
</div>
Fiddle: https://jsfiddle.net/6ardv95r/
UPDATE:
The bubbling nature of events was brought up however this doesnt answer why this behaviour still occurs even when the html is turned into this:
<div class="container">
<div class="background" onmouseover="test(this)">
</div>
<div class="content">
</div>
</div>
In this case the content class doesnt capture any hover event but still no event triggers the background class. Upon removal of the content class the background class works as expected..
Browser events work through a process called "bubbling" - they start at the most specific tag and then work their way up the tree (from child to parent to grand-parent, etc) until they reach the root tag (usually <html>).
In your case, mouseover and mouseout events get triggered inside the "content" div and bubble up, but they aren't contained within the "background" div in terms of the DOM tree, even if they are contained visually (with the content rectangle being drawn as "inside" the background rectangle).
In this case the "content" div appears after the "background" div, so it is rendered "on top" and gets all the events, while "background" gets none. If you want the background to get the events too, put the "content" div inside the "background" div.
More info on event bubbling here: https://javascript.info/bubbling-and-capturing
I have this simple issue: a div that contains a link, and the div has an onclick function defined. However, when I click the link, I just want to follow the link, and not fire the containing div's function.
Fiddle
HTML
<div>
Google
</div>
JQuery
$('div').click(function() {
alert("test");
});
CSS
div {
height: 100px;
width: 200px;
border: 1px solid red
}
So here, when I click the div, an alert is shown: that's fine. When the link is clicked, I don't want the alert to show.
How to avoid this?
You can apply event.stopImmediatePropagation(); to the link. According to the API, this keeps the rest of the handlers from being executed and prevents the event from bubbling up the DOM tree (https://api.jquery.com/event.stopimmediatepropagation/).
Here is the fiddle: http://jsfiddle.net/dxrdrqrc/
Let's say I have Div A, with a child Div B. Both have a mouse click assigned to them. How might I be able to click Div A, and have both Div A's and Div B's events triggered? I've looked into event bubbling but all my attempts to make this happen have failed so far.
I am assigning mouse events as such:
elem.addEventListener( 'click', myResponseFunction, true );
I tried setting the bubbling to true and false on both or one or the other and have had no success. Is this possible? No jQuery solutions please.
Further clarification:
Consider an expandable ad with tiles in the collapsed portion that can either be video or synopsis, determined at runtime from a data provider. I want the ad to expand when clicked anywhere in the collapsed portion, but if a "view video" button or "view synopsis" button is below the click-to-expand button, I'd like the ad to advance to the appropriate view after expanding. I desired a cleaner approach, if possible, than putting the expand action on each tile's call-to-action button. Each tile is a div with a background image and call-to-action button, all covered by and click-to-expand button.
Click events are only triggered on those elements that are under mouse/touch pointer.
Bubbling (up) means that once a child element has processed a click event it then triggers another event of the same type on it's parent element. This process repeats all the way up to the document element. What you want is bubbling down. Unfortunately that concept doesn't exist in JavaScript.
A pragmatic solution is to iterate over all child nodes and trigger click events manually when a parent node is clicked. There will be one side effect: mouse events bubble up by default and so when a child node is clicked, it's parent will also receive a click event. This can be easily solved by stopping event propagation further up inside of a child click event handler.
Here is a complete sample:
document.querySelector('.parent').addEventListener('click', function(e) {
console.log('hello from parent');
var children = this.children;
[].forEach.call(children, function(elem) {
elem.click();
});
});
document.querySelector('.child').addEventListener('click', function(e) {
e.stopPropagation();
console.log('hello from child');
});
.parent {
height: 300px;
width: 400px;
background-color: lightblue;
}
.child {
position: relative;
top: 100px;
left: 100px;
height: 100px;
width: 200px;
background-color: lightyellow;
}
<div class='parent'>
<div class='child'></div>
</div>
Seeing as though Nested Anchor Tags are not possible, could Javascript be utilized to have a Div Box hyperlink to Page-A, while having a word of a Text within the Div Box hyperlink to Page-B?
Have tried working with the following Javascript (works for hyperlinking the Box or the Text, but not both):
<script type="text/javascript">
// Content-Link Click Events
$('.content-link-page-a').click(function(){
window.location.href = "page-a.html";
});
$('.content-link-page-b').click(function(){
window.location.href = "page-b.html";
});
</script>
Here's some CSS:
<style>
.box {
height: 50px;
width: 100px;
border: 1px solid #000;
}
</style>
And here's the HTML:
<div class="box content-link-page-a">
<div id="username" class="content-link-page-b">UserName</div>
</div><!--/box-->
You should remove the A from around the inner DIV, give it a bigger z-index than the outer, and handle the inner click event with calling event.stopPropagation to prevent bubbling of the event to the outer div. Here is a fiddle to solve the task.
Sample for the inner handler:
$('.content-link-page-b').click(function(e){
alert("page-b.html");
e.stopPropagation();
});
EDIT: In my comment above, I mentioned e.preventDefault() call. I didn't mean that, because that means the native DOM element's handler will be prevented, and not the jQuery event bubbling.