Avoid mousemove on absolutely positioned children elements - javascript

I am trying to understand mousemove Event on absolute elements.
I made a Codepen to demonstrate what i wanted.
I need mousemove to be captured on #main element, But not on any of its children that are positioned absolutely.
HTML:
<div id="main">
<div class="btn">Click Me</div>
</div>
<div id="output">
</div>
JS:
$(document).ready(function(){
$('#main').on('mousemove',function( e ) {
var msg = "mouse move ";
msg += e.pageX + ", " + e.pageY;
$( "#output" ).html(msg);
});
});

Simply check who's the target in your event handler, and if it is one of those you want to block the event, return early.
In current configuration, it is the same as checking if the target is indeed #main, a.k.a jQuery's $event.currentTarget.
$('#main').on('mousemove', function(e) {
// here we only want the events of #main
// so any other target is irrelevant
if (e.target !== e.currentTarget) return;
var msg = "mouse move ";
msg += e.pageX + ", " + e.pageY;
$("#output").html(msg);
});
$('#main').on('mouseout', function() {
$("#output").html('');
});
$('#main>.btn').on('click', e=> $("#output").html('can still click'));
#main {
float: left;
background: yellow;
width: 400px;
height: 400px;
position: relative;
}
#main .btn {
position: absolute;
top: 20px;
left: 20px;
z-index: 2;
border: 0;
background: blue;
color: #FFF;
}
#main .btn .innerbtn {
padding: 10px;
}
#output {
display: inline-block;
background: #efefef;
width: 200px;
position: absolute;
right: 0;
pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="main">
<div class="btn">
<div class="innerbtn">Click Me</div>
</div>
</div>
<div id="output">
</div>

Related

detect event on 2 overlapping sibling elements?

I have 2 overlapping siblings like this:
document.querySelector("#item1").addEventListener('mouseup',()=>{
console.log("Mouseup item 1!");
});
document.querySelector("#item2").addEventListener('mouseup',()=>{
console.log("Mouseup item 2!")
},true);
#item1{
height:10rem;
width:10rem;
background-color:red;
position:absolute;
z-index:-2;
}
#item2{
height:10rem;
width:10rem;
background-color:green;
position:relative;
top:2rem;
}
<div id="item1"></div>
<div id="item2"></div>
whenever I mouseup on item2 I want item1 mouseup event to also be triggered if mouse is within item1
( Basically I want mouseup to be triggered on whatever divs the mouse is within regardless of which is overlapping what )
How do I achieve this?
Using elementsFromPoint as 'pointed out' by #Teemu in the comments I came up with this:
document.querySelector("#wrapper").addEventListener('mouseup', (event) => {
let els = document.elementsFromPoint(event.clientX, event.clientY);
els.forEach(el => {
if (el.id != '' && el.id != 'wrapper')
console.log(el.id)
})
});
#item1 {
height: 10rem;
width: 10rem;
background-color: red;
position: absolute;
}
#item2 {
height: 10rem;
width: 10rem;
background-color: green;
position: relative;
top: 2rem;
}
#wrapper {
background-color: blue;
height: 20rem;
width: 20rem;
}
<div id="wrapper">
<div id="item1"></div>
<div id="item2"></div>
</div>

Simple hover controls

So I have few squares, and when I hover over one, i want a menu to show up. Then, when I hover out, i want it to disappear. Simple right?
So the problem is when I move my mouse very fast over them, some of them stay... hidden. I can resign from squares going transparent, but my mouseout event is not fired right too.. because my mouse is far away, and my black menu is still on top of a square!
So fading out pink squares is more to show the issue. I am most troubled by black square not disappearing.
$(document).ready(function() {
$('.square').mouseenter(faceon);
$('#hover_controls').mouseleave(faceout);
});
function faceon() {
$(this).stop().clearQueue().fadeTo("slow", 0.15);
$('#hover_controls').stop().clearQueue().css({
top: $(this).offset().top + "px",
left: $(this).offset().left + "px",
display: 'block'
}).fadeTo("fast", 1);
}
function faceout(event) {
var e = event.toElement || event.relatedTarget;
if (e.parentNode == this || e == this) {
return;
}
$('.square').stop().clearQueue().fadeTo("slow", 1);
$('#hover_controls').stop().clearQueue().fadeTo("fast", 0, function() {
$(this).hide();
});
}
.square {
height: 72px;
width: 72px;
background: pink;
margin: 5px;
display: inline-block;
}
#hover_controls {
display: none;
height: 62px;
width: 62px;
opacity: 0;
padding: 5px;
position: fixed;
background: #000;
border-radius: 10px;
z-index: 2;
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='hover_controls'>
<a href='#' onclick='alert("aaa");'>a</a>
<a href='#' onclick='alert("bbbb");'>b</a>
</div>
<div class="list">
<div class="square"></div>
<div class="square"></div>
<div class="square"></div>
</div>
Any ideas?
Replace mouseover and mouseout with mouseenter and mouseleave respectively. I hope this helps.
Change the event handler, fix issue wtih e in the conditional if mouse out fast where e is null.
The complication here is the mouseenter/mouseleave and the animation - note that those events are on different elements, one of which you show/hide when the events trigger. Thus it is likely the mouseleave event does not properly trigger ALL the time due to the element it is hooked to not being visible on a "fast mouse" action behavior.
$(document).ready(function() {
$('.square').on("mouseenter", faceon);
$('#hover_controls').on("mouseleave", faceout);
});
function faceon() {
$(this).stop().clearQueue().fadeTo("slow", 0.15);
$('#hover_controls').stop().clearQueue().css({
top: $(this).offset().top + "px",
left: $(this).offset().left + "px",
display: 'block'
}).fadeTo("fast", 1);
}
function faceout(event) {
var e = event.toElement || event.relatedTarget;
if (e && (e.parentNode == this || e == this)) {
return;
}
$('.square').stop().clearQueue().fadeTo("slow", 1);
$('#hover_controls').stop().clearQueue().fadeTo("fast", 0, function() {
$(this).hide();
});
}
.square {
height: 72px;
width: 72px;
background: pink;
margin: 5px;
display: inline-block;
}
#hover_controls {
display: none;
height: 62px;
width: 62px;
opacity: 0;
padding: 5px;
position: fixed;
background: #000;
border-radius: 10px;
z-index: 2;
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='hover_controls'>
<a href='#' onclick='alert("aaa");'>a</a>
<a href='#' onclick='alert("bbbb");'>b</a>
</div>
<div class="list">
<div class="square"></div>
<div class="square"></div>
<div class="square"></div>
</div>

Not able to remove parent div [duplicate]

This question already has answers here:
Event binding on dynamically created elements?
(23 answers)
Closed 5 years ago.
I am working on a project and there I am getting a value from input tag and then insert input value in a div and appending on screen with children element.
And What I want that when user click on children element then parent div would be removed and for this I'm using a function. That is working when I am using by default a section but when I append a section and then click on that's children where a function call like when user click on it's children parent section would be removed but my functionality not working.
$('#btn').click(function() {
var menuFieldName = $('#text').val();
$('.div').append('<div class="a">' + menuFieldName + '<span>X</span></div>');
$('#text').val('');
});
$('.div .a span').on('click', function() {
$(this).parent().remove();
});
.a {
display: inline-block;
padding: 5px 35px 5px 10px;
position: relative;
background: #eee;
border-radius: 20px;
margin: 10px;
}
.a span {
position: absolute;
top: 0;
right: 0;
background: #333;
color: #fff;
height: 28px;
width: 28px;
text-align: center;
line-height: 28px;
border-radius: 30px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="div">
<div class="a">Test <span>X</span></div>
</div>
<input type="text" id="text">
<button id="btn">Add</button>
https://jsfiddle.net/jafaruddeen/rag71ma0/
You are appending elements dynamically but you are not attaching any event handler to the newly added elements. To solve this you can use event delegation, you can attach events to .div like $('.div').on('click', '.a span', function() {
$('#btn').click(function() {
var menuFieldName = $('#text').val();
$('.div').append('<div class="a">' + menuFieldName + '<span>X</span></div>');
$('#text').val('');
});
$('.div').on('click', '.a span', function() {
$(this).parent().remove();
});
.a {
display: inline-block;
padding: 5px 35px 5px 10px;
position: relative;
background: #eee;
border-radius: 20px;
margin: 10px;
}
.a span {
position: absolute;
top: 0;
right: 0;
background: #333;
color: #fff;
height: 28px;
width: 28px;
text-align: center;
line-height: 28px;
border-radius: 30px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="div">
<div class="a">Test <span>X</span></div>
</div>
<input type="text" id="text">
<button id="btn">Add</button>
The reason you can't remove it is because when you register the event, the element on which you try to register it doesn't exist yet.
You need to use event delegation
$('body').on('click', '#my-element', function(){...});
you have to call click function after append.. or call click function globally(body element) and match the span..
$(document).ready(function(){
$('#btn').on('click',function(){
var menuFieldName = $('#text').val();
$('.div').append('<div class="a">'+menuFieldName+'<span class="close">X</span></div>');
$('.div .a span').on('click', a);
$('#text').val('');
});
$('.div .a span').on('click', a);
function a() {
$(this).parent().remove();
}
});
check your js fiddle. fixed it -> https://jsfiddle.net/jafaruddeen/rag71ma0/

Custom Drag & Drop not working perfectly

I want to drag a div and drop anywhere in its parent div . For dragging I use css style
draggable="true"
and for drop, I use 'mousemove' event X and Y values and use this values for div top and left .The code I used is
$(".drop").mousedown(function () {
$(this).mousemove(function (e) {
var k = e.clientX ;
var f = e.clientY;
$(".drop").text(k+ ", " + f);
$(".drop").css("top",f);
$(".drop").css("left",k);
});
}).mouseup(function () {
$(this).unbind('mousemove');
}).mouseout(function () {
$(this).unbind('mousemove');
});
.drop{
position: absolute;
left: 300;
top: 200; /* set these so Chrome doesn't return 'auto' from getComputedStyle */
width: 200px;
background: rgba(255,255,255,0.66);
border: 2px solid rgba(0,0,0,0.5);
border-radius: 4px; padding: 8px;
z-index: 3;
}
.gridPart{
padding: 20px;
background-color: #FFF;
border-radius: 5px;
margin: auto;
margin: 20px;
padding-right: 0px;
padding-bottom: 3px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="gridpart">
<div class="drop" draggable="true" ></div>
<div>
Now it's drag & drop if I drag with increasing left value. But if I drag with decreasing left value it's not dropping. And how I stop the drag if it reach the end of the main div(GridPart)?
I have fixed your code. All you did is quite good but you should have to use the mousemove event with $(document) element and not with the div. Since when you drag backwards, mouse movement is going out of the div and so its no longer dragging.
Also, as you used custom dragging, you don't need to use draggable="true".
$(".drop").mousedown(function () {
$(document).mousemove(function (e) {
var k = e.clientX;
var f = e.clientY;
$(".drop").text(k+ ", " + f);
$(".drop").css("top", f + 'px');
$(".drop").css("left", k + 'px');
});
});
$(document).mouseup(function () {
$(document).unbind('mousemove');
});
.drop{
position: absolute;
left: 300;
top: 200; /* set these so Chrome doesn't return 'auto' from getComputedStyle */
width: 200px;
background: rgba(255,255,255,0.66);
border: 2px solid rgba(0,0,0,0.5);
border-radius: 4px; padding: 8px;
z-index: 3;
}
.gridPart{
padding: 20px;
background-color: #FFF;
border-radius: 5px;
margin: auto;
margin: 20px;
padding-right: 0px;
padding-bottom: 3px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="gridpart">
<div class="drop" ></div>
<div>
Simply use the JQueryUi Draggable:
https://jqueryui.com/draggable/
UPDATE: sample code here:
http://embed.plnkr.co/5W3ACU/
I think what i have discerned from your question you are trying to do, is limit dragging to within the .gridpart div.
The key was moving the drag detection to the container div, and then moving the drag component based on the mousedown position
JSFIDDLE
JS
$(".gridpart").mousedown(function () {
var containerDims = $(this)[0].getBoundingClientRect();
var dropEl = $(this).find('.drop');
// measure the size of the drop element
var dropDims = dropEl[0].getBoundingClientRect()
$(this).mousemove(function (e) {
// position the element centered under the cursor
var k = e.clientX - dropDims.width / 2;
var f = e.clientY - dropDims.height / 2;
if( k >= 0 && k <= containerDims.width - dropDims.width){
dropEl.css("left",k);
}
if(f >= 0 && f <= containerDims.height - dropDims.height){
dropEl.css("top", f);
}
dropEl.text(k + ', ' + f);
});
}).mouseup(function () {
$(this).unbind('mousemove');
});
CSS
.drop{
position: absolute;
left: 0;
top: 20px;
width: 200px;
background: rgba(255,255,255,0.66);
border: 2px solid rgba(0,0,0,0.5);
border-radius: 4px; padding: 8px;
z-index: 3;
/* prevent 'shadow' drag preventing mouseup firing */
-webkit-user-drag: none;
-khtml-user-drag: none;
-moz-user-drag: none;
-o-user-drag: none;
user-drag: none;
}
.gridpart{ /* correct camelcase typo */
background-color: #F00;
border-radius: 5px;
margin: 20px;
padding-right: 0px;
position: relative;
height: 58px;
}
HTML
<div class="gridpart">
<div class="drop" draggable="true">0, 0</div>
<div>

jQuery update (1.7) breaks event coords on touch event?

This jsfiddle reproduces the problem and allows you to quickly switch between 1.6.4 and 1.7.1.
You'll see that LIs stop being detected, because the coords are undefined after switching to 1.7.1
http://jsfiddle.net/eHHgP/2/
How can I fix this problem without downgrading?
body{
font-family: sans-serif;
}
#other{
position: absolute;
height: 300px;
width: 300px;
background: rgba(0,0,0,0.5);
}
#other ul{
position: absolute;
top: 50px;
right: 50px;
bottom: 50px;
left: 50px;
width: 200px;
height: 200px;
}
#other li{
display: block;
margin: 25px;
height: 50px;
width: 50px;
color: white;
background: rgba(0,0,0,0.5);
float: left;
<div id="other">
<ul>
<li>LI</li>
<li>LI</li>
<li>LI</li>
<li>LI</li>
</ul>
</div>
<div id="output">
output
<div>
$(document).bind('touchmove', function(event){
event.preventDefault();
});
$('#other').bind('touchstart touchmove', function(event){
element = document.elementFromPoint(event.pageX, event.pageY);
console.log(event);
if(element.nodeName === 'LI'){
$('#output').html('LI');
}else{
$('#output').html('NOT LI');
}
});
It turns out that in 1.7, only events which pass this regexp have certain "mouse properties" (like .pageX) passed through to the jQuery event object:
/^(?:mouse|contextmenu)|click/
Obviously, touchstart etc. don't pass this regexp. So you'd have to mark these events as being mouse events yourself, as jQuery does here. You can do it this way if you want to go for conciseness:
// add more if necessary, I don't know much about touch events
$.each("touchstart touchmove touchend".split(" "), function(i, name) {
jQuery.event.fixHooks[name] = jQuery.event.mouseHooks;
});
Also another way to handle this is using the proper e.changedTouches. So it would work like this:
if (typeof e.changedTouches !== 'undefined') {
pageX = e.changedTouches[0].pageX;
pageY = e.changedTouches[0].pageY;
} else {
pageX = e.pageX;
pageY = e.pageY;
}
Hope this helps.

Categories

Resources