Browser event does not bubble - javascript

I want to make the drag drop to the element,and I dot not want the parent of this element capture the click or drag event, so I use the bubble model, however the element which I want to drag contain a child who own the same size (width, height, left...) of this element.
For example:
<div id="div_con" style="left: 20px; top: 50px; width: 181px; height: 357px; position: absolute; z-index: 10; cursor: pointer;" class="drag">
<img src="test.PNG" id="Over_Label_1912694_Img" style="left: 0px; top: 0px; width: 181px; height: 357px; position: relative;">
</div>
div#div_con is the element I want to drag, but since the div#div_con and the img have the same size, so user can never click the div#div_con. Since the img is above it.
So I bind the mouseDown, mouseMove, mouseUp events to the whole document:
document.onmousedown = OnMouseDown;
document.onmouseup = OnMouseUp;
In my opinion,when user click the img under the div#div_con, the mouseDown event will bubble to div#div_con.
Since I just want to drag the div#div_con,so I make a check in the mouseDown handler:
if ((e.button == 1 && window.event != null || e.button == 0) && target.className == 'drag')
{ //do the start the move}
But it does not work.
This is the complete example:
http://jsfiddle.net/5SCwG/

But it is bubbling. That's why document is receiving the event to begin with. The problem you're experiencing is that event.target refers to the object clicked, and event.currentTarget refers to the object listening and neither one of those are your div.
You will either need to use an event listener on the div directly, or you'll need to get target.parentElement and then use that as _dragElement.
Check it out.

If you specify the image as background-image of the DIV and remove the IMG drag & drop works: http://jsfiddle.net/HxaJ4/

Related

How to get "Pointermove" delegation to work in Safari iOS on parent/child?

I've run into a problem and haven't been able to find a workaround yet. I'm trying to use an event delegate with "pointermove" on a parent container and I want to know when the event crosses from a child to the parent container and vice versa.
This works well on desktop browsers, but when I try in Safari iOS it seems like the event target gets "stuck" on whatever first started the pointermove. When the pointermove crosses to the parent/child boundary the target doesn't change. Any ideas?
Example code:
const outer = document.getElementById("outer");
outer.addEventListener("pointermove", (e) => console.log(e.target.id))
body {
touch-action: none;
}
#outer {
height: 500px;
width: 500px;
background-color: #AAAAFF;
}
#inner {
height: 200px;
width: 200px;
background-color: #AAFFAA;
}
<div id="outer">
<div id="inner">
</div>
</div>
Looks like this has been an issue for a long time. Touchmove works the same way as Pointermove which is why I wasn't seeing results for this question. Here's another stack overflow post with the workaround which is to use document.elementFromPoint like e.g.:
const outer = document.getElementById("outer");
outer.addEventListener("pointermove", (e) => {
actualTarget = document.elementFromPoint(e.clientX, e.clientY);
console.log(actualTarget.id);
})

How can I stop an event from being triggered on a child element rather than adding pointer events none?

How can I prevent the element within an element triggering the element within?
Is there a better way than adding pointer-events none?
const selectors = {
scrollContainer: '[data-scroll-container]',
scrollTrigger: '[data-scroll-trigger]',
scrollNext: 'data-next',
scrollBack: 'data-back',
};
/**
* Main
*/
const scrollTrigger = [...document.querySelectorAll(selectors.scrollTrigger)];
const handleScroll = ({ target }) => {
console.log(target);
if (target.hasAttribute(data-next)) {
console.log(target)
}
};
<button data-scroll-trigger data-next>
<svg>//some svg here//</svg>
</button>
Difficult to determine from the code provided and feels like there may be some design issues, but I would simply add the handler on the outermost container and then use currentTarget property or target property as needed.
The difference being target is the element that triggered the event and currentTarget is the element that has the handler attached to it. Child elements will propagate events up to parent handlers. If you want to get the parent, use currentTarget.
There are numerous ways to test if the element triggering is the element that the handler is attached to, but here is a very basic demo:
document
.querySelector('#outer')
.addEventListener('click', (e) => {
console.log(e.currentTarget !== e.target);
if (e.currentTarget !== e.target) {
e.preventDefault();
}
});
#outer {
display: inline-block;
width: 200px;
height: 200px;
background: red;
}
#inner {
display: inline-block;
width: 100px;
height: 100px;
background: blue;
}
<a id="outer" href="http://google.com">
<a id="inner" />
</a>

How to drag and drop object no jquery

Ok, I feel like this should have already been asked on stackoverflow, but apparently it hasn't. How do you make an object draggable using no jQuery?
I understand how to make an object move on the hovering of the mouse so it contantly follows it, and tried to apply it to mousedown instead of mousemove and set it on an interval of every 10 milliseconds, but with no success.
So here is what I have:
document.querySelector(".box").addEventListener(function(e) {
let s = document.querySelector(".box");
var e = e || window.event;
let run = setInterval(function() {
s.style.marginLeft = e.clientX + "px";
s.style.marginTop = e.clientY + "px";
getMouseCoords(e);
}, 10);
});
So how would I drag and drop an object without any jQuery?
Follow this. It uses only pure JavaScript.
Simply you can drag div content
<div id="draggable-element">Drag me!</div>
Link for Draggable Project
There is a really good codepen example I've used in the past for this:
https://codepen.io/byronglover/pen/oxjgEK
Step 1 - create containers for the objects
<!--First Drop Target-->
<div data-drop-target="true">
<div id="box1" draggable="true" class="box navy"></div>
<div id="box2" draggable="true" class="box red"></div>
<div id="box3" draggable="true" class="box green"></div>
<div id="box4" draggable="true" class="box orange"></div>
<div id="box5" draggable="true" class="box navy"></div>
<div id="box6" draggable="true" class="box red"></div>
<div id="box7" draggable="true" class="box green"></div>
<div id="box8" draggable="true" class="box orange"></div>
</div>
<!--Second Drop Target-->
<div data-drop-target="true"></div>
Step 2 - apply some javascript invoking draggable and data-drop-target and event listeners
//Function handleDragStart(), Its purpose is to store the id of the draggable element.
function handleDragStart(e) {
e.dataTransfer.setData("text", this.id); //note: using "this" is the same as using: e.target.
}//end function
//The dragenter event fires when dragging an object over the target.
//The css class "drag-enter" is append to the targets object.
function handleDragEnterLeave(e) {
if(e.type == "dragenter") {
this.className = "drag-enter"
} else {
this.className = "" //Note: "this" referces to the target element where the "dragenter" event is firing from.
}
}//end function
//Function handles dragover event eg.. moving your source div over the target div element.
//If drop event occurs, the function retrieves the draggable element’s id from the DataTransfer object.
function handleOverDrop(e) {
e.preventDefault();
//Depending on the browser in use, not using the preventDefault() could cause any number of strange default behaviours to occur.
if (e.type != "drop") {
return; //Means function will exit if no "drop" event is fired.
}
//Stores dragged elements ID in var draggedId
var draggedId = e.dataTransfer.getData("text");
//Stores referrence to element being dragged in var draggedEl
var draggedEl = document.getElementById(draggedId);
//if the event "drop" is fired on the dragged elements original drop target e.i.. it's current parentNode,
//then set it's css class to ="" which will remove dotted lines around the drop target and exit the function.
if (draggedEl.parentNode == this) {
this.className = "";
return; //note: when a return is reached a function exits.
}
//Otherwise if the event "drop" is fired from a different target element, detach the dragged element node from it's
//current drop target (i.e current perantNode) and append it to the new target element. Also remove dotted css class.
draggedEl.parentNode.removeChild(draggedEl);
this.appendChild(draggedEl); //Note: "this" references to the current target div that is firing the "drop" event.
this.className = "";
}//end Function
//Retrieve two groups of elements, those that are draggable and those that are drop targets:
var draggable = document.querySelectorAll('[draggable]')
var targets = document.querySelectorAll('[data-drop-target]');
//Note: using the document.querySelectorAll() will aquire every element that is using the attribute defind in the (..)
//Register event listeners for the"dragstart" event on the draggable elements:
for(var i = 0; i < draggable.length; i++) {
draggable[i].addEventListener("dragstart", handleDragStart);
}
//Register event listeners for "dragover", "drop", "dragenter" & "dragleave" events on the drop target elements.
for(var i = 0; i < targets.length; i++) {
targets[i].addEventListener("dragover", handleOverDrop);
targets[i].addEventListener("drop", handleOverDrop);
targets[i].addEventListener("dragenter", handleDragEnterLeave);
targets[i].addEventListener("dragleave", handleDragEnterLeave);
}
And Finally some CSS to tie it all together
h2 {
color: #a7a3a4;
margin-left: 80px;
}
[data-drop-target] {
height: 400px;
width: 200px;
margin: 25px;
background-color: gainsboro;
float: left;
}
.drag-enter {
border: 2px dashed #000;
}
.box {
width: 100px;
height: 100px;
float: left;
}
.box:nth-child(3) {
clear: both;
}
.navy {
background-color: navy;
}
.red {
background-color: firebrick;
}
.green {
background-color: darkgreen;
}
.orange {
background-color: orange;
}
Summary
The long and short of it is that the draggable content needs to have some sort of event listener to bind to it for this to work effectively.
Let me know if you have any other questions and I will do my best to help!

How can I make the parent div draggable

I have a div containing three buttons. The div needs to be draggable, so that you can drag all three buttons around the screen together. That works fine, but the problem is that when I click on of the individual buttons it inherits the draggable id and it is draggable on it's own. I do not want that to happen. So my question is: how do I make my buttons draggable, but make them always stay together and keep them clickable. I added the code below, but here is a JSFiddle: http://jsfiddle.net/2ga50vvt/
So to be clear: the div also needs to be draggable through dragging one of the individual buttons, but then the rest of the div needs to stick with it. Now dragging an individual button only moves the button.
P.S. I do not want to use JQuery UI
HTML:
<div id="draggable" class="ui-widget-content">
<button ng-click="menu.shown = !menu.shown">MENU</button>
<br>
<button ng-click="disconnect()">CLOSE</button>
<br>
<button ng-click="">KEYS</button>
</div>
JS
$(document).ready(function() {
var $dragging = null;
$('body').on("mousedown", "#draggable", function(e) {
$(this).attr('unselectable', 'on').addClass('dragged');
var el_w = $('.dragged').outerWidth(),
el_h = $('.dragged').outerHeight();
$('body').on("mousemove", function(e) {
if ($dragging) {
$dragging.offset({
top: e.pageY - el_h / 2,
left: e.pageX - el_w / 2
});
}
});
$dragging = $(e.target);
}).on("mouseup", ".dragged", function(e) {
$dragging = null;
$(this).removeAttr('unselectable').removeClass('dragged');
});
});
CSS:
body {
padding: 50px;
}
.dragged {
background-color: yellow;
}
#draggable {
position: fixed;
width: 150px;
height 150px;
padding: 0.5em;
background: red;
background-color: black;
z-index: 1000;
cursor: move;
float: left;
}
Update 1
This is a working solution: http://jsfiddle.net/2ga50vvt/3/
However when I click on the div and start dragging the center of the div jumps to my cursor. It works great, but it looks a bit wonky. Is there a way to prevent the div from moving to my cursor?
Your help is most welcome.
You can read the target property of the event and return false to avoid all not #draggable to be draggable.
if(e.target.id !== "draggable") {
return false;
}
The edited fiddle:
http://jsfiddle.net/2ga50vvt/1/
It works perfectly, but one suggestion: don't target with ids because with this code you can't drag more of one element (ids must be unique), so the workaround is to write an attribute or a classname and play with it.
Good luck.
Use $dragging = $('#draggable'); instead of $dragging = $('e.target');
It will drag div if you try to drag using cursor on button. It will drag #draggable instead of target.
Working Fiddle
Presuming you're opposed to JQueryUI for it's file size, I'd still recommend a prebuilt solution because why reinvent the wheel?
Draggabilly is a really nifty library that I've used when resource size has been an issue. It's 20k minified (obviously even smaller gzipped) and available on a CDN - which in itself has lots of benefits e.g. caching.
$(function() {
$( "#draggable" ).draggabilly();
});
There's a few CSS hooks, different options, events etc.
JSFiddle here

Trigger specific mouse event on another element

I have a web application containing an image on which a mousewheel event is caught in order to zoom the image precisely on the point where the cursor is.
On top of this image, I display a custom tooltip which is just a div containing text. When I mousewheel on the tooltip, the image is not zoomed.
I tried to bind the image mousewheel event on the tooltip but then, the offsetX and offsetY of the event correspond to the cursor position relative to the tooltip and not relative to the image.
How can I:
either get the image offsetX and offsetY, even when the cursor is over the tooltip? or
prevent the tooltip to catch the mousewheel event before the image?
EDIT:
Actually, Before, I could select the tooltip by clicking on it; but by adding the CSS style 'pointer-events:none' (suggested by Aramil Rey), the click event has no effects (obviously).
Therefore, how can I:
prevent the tooltip to catch the mousewheel event before the image?
and still let the tooltip catch the click event?
Did you try using CSS: pointer-events:none; on the tooltip?
JS Fiddle
Try hovering on the red div, and you will notice that it won't trigger its attached event, and intead it will trigger yellow div on mouseeenter event if you enter that div, even if your cursor is over the red div.
$('.asd').on('mouseenter', function() {
alert('asd');
});
$('.ddaa').on('mouseenter', function() {
alert('ddaa');
});
.ddaa {
padding-top: 15px;
background-color: yellow;
}
.asd {
position: absolute;
width: 100%;
pointer-events:none;
padding-top: 10px;
top: 5px;
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="ddaa">
</div>
<div class="asd">
</div>
I assume currently you are getting offsetX and offsetY from event.target. Set an ID to the image and replace event.target with $("#imageID")[0]. Better yet, jquery provides an offset function.
var image = $('#image');
image.add('.tooltip').bind('mousewheel', function (event) {
event.preventDefault();
var offset = image.offset();
var mouseX = event.pageX - offset.left;
var mouseY = event.pageY - offset.top;
// zoom stuff
});

Categories