How to get top level object under the mouse function? - javascript

Title says it all. I've got child div's with absolute positions inside a relative parent div, and would like to know whether the mouse is over a child or a parent div at a "random" point in time.
Hypothetically, I'd like to call the .mouseover method and perform a .hasclass test on the highest level object to see if it has the child class or not. However, .mouseover is an event handler, thus not something I could just call to get the relevant information.
Example HTML below:
$(document).ready(function() {
$(".child").draggable();
setTimeout(doSomething, 31415);
});
var doSomething = function() {
// Edit content based on what is underneath the mouse
}
.parent {
width: 100%;
height: 1000px;
position: relative;
background: #f0f0f0;
}
.child {
width: 300px;
height: 100px;
position: absolute;
background: #cccccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.11.4/themes/ui-lightness/jquery-ui.css">
<script src="http://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>
<div class="parent">
<div class="child"></div>
<div class="child"></div>
</div>

Getting an element from a position is what the document.elementFromPoint function was designed to do:
document.elementFromPoint(mousePosition.x, mousePosition.y);
To get the current mouse position, attach a listener to mousemove (as far as I know there is no native method to extract mouse coordinates without a mouse event). Here's an example fiddle showing this: https://jsfiddle.net/xsLwt8Ld/

If I understood correctly, you want to know if at any given time, the mouse is over the child or directly over the parent. You could achieve it by using the :hover pseudoclass
Create a function that checks if there is any .child that has the :hover class:
If there is, that means that the mouse is over a .child (and you have the element) and there's no need to check the parent.
If there isn't, then check if there is any .parent element that also has the class that you created:
If there is: the mouse is over a .parent but not over a .child;
If there is not: the mouse i not over a .parent or a .child.
The code to achieve this is simple:
function checkMouseOver() {
if ($(".child:hover").length) {
// mouse over a .child
} else if ($(".parent:hover").length) {
// mouse over a .parent (but not over .child)
} else {
// mouse not over a .parent or .child;
}
}
A simple working demo:
$(".child").draggable();
// Edit content based on what is underneath the mouse
function checkMouseOver() {
if ($(".child:hover").length) {
alert("You were over " + $(".child:hover").text());
} else if ($(".parent:hover").length) {
alert("You were over " + $(".parent:hover").attr("id"));
} else {
alert("You are not over a .parent or .child");
}
}
.parent {
width: 100%;
height: 1000px;
position: relative;
background: #f0f0f0;
}
.child {
width: 300px;
height: 100px;
position: absolute;
background: #cccccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.11.4/themes/ui-lightness/jquery-ui.css">
<script src="http://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>
<button onclick="checkMouseOver()">Check where the mouse is</button>
<div class="parent" id="parent1">
<div class="child">Child 1</div>
<div class="child">Child 2</div>
</div>
<div class="parent" id="parent2">
<div class="child">Child 3</div>
<div class="child">Child 4</div>
</div>
(Click on the page and press tab until you get into the button, then mouse over the different elements and press Enter to trigger the funtion)

Related

Hover on two elements using jQuery

I have two <div> elements attached to each other, I mean there is no space between them.
<div id="box1">1</div>
<div id="box2">2</div>
And I have this jQuery code:
$('#box1 , #box2').hover(function() {
console.log("Hovered")
}, function() {
console.log("Not")
});
My problem is when I move the mouse between box1 and box2, I still get on console log "Not".
I want those divs to be considered as one element so when I move the mouse between them I don't get on console log "Not".
Thanks in advance!
I want those divs to be considered as one element
Well, quite simply, they aren't. And they can't be. That's not how HTML and CSS works.
The hover event is triggered one for each individual element bound to the event handler. And every time you leave one of those elements it will print the "not" output as per your instructions.
There is no "fix" for this in the exact way you described, but there are alternative approaches. An obvious solution is to wrap them both in an outer div and bind the hover event to that instead. Then the whole area will be considered as one element (because it literally is). Demo:
$('#boxcontainer').hover(function() {
console.log("Hovered")
}, function() {
console.log("Not")
});
#boxcontainer {
border: solid 1px black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="boxcontainer">
<div id="box1">1</div>
<div id="box2">2</div>
</div>
friend check the code below. I think it will work for you. As you have dai you have an absolute position div you must need a parent div and the parent div position must be relative. For doing that you have to add just a simple CSS code position: relative;. You also need to do some changes to your jquery code. You can just hover on the parent div and it will do your work. Hope this code will help you.
//Box 1 Demo
$('#boxParrent1').hover(function() {
console.log("Hovered")
}, function() {
console.log("Not")
});
//Box 2 Demo
$('#boxParrent2').hover(function() {
console.log("Hovered")
}, function() {
console.log("Not")
});
/*Main Code that are needed*/
#boxParrent1, #boxParrent2 {
position: relative;
}
/*Codes Just used to give you a demo*/
#boxParrent1, #boxParrent2{
display: flex;
margin-bottom: 50px;
border: 1px solid #000;
}
#boxParrent1{
width: 200px;
}
#boxParrent2{
width: 210px;
}
#box1, #box2, #box3, #box4{
background: tomato;
width: 100px;
height: 100px;
display: grid;
justify-content: center;
align-items: center;
font-family: Arial;
font-size: 50px;
color: #fff;
cursor: pointer;
}
#box2, #box4{
position:absolute;
top: 0;
left:100px;
background: #02dce6;
}
#box4{
left:110px;
background: #02dce6;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="boxParrent1">
<div id="box1">1</div>
<div id="box2">2</div>
</div>
<div id="boxParrent2">
<div id="box3">3</div>
<div id="box4">4</div>
</div>
Try to place your 2 div's in one super div
<div id="super">
<div id="box1">1</div>
<div id="box2">2</div>
</div>
$('#super').hover(function() {
console.log("Hovered")
}, function() {
console.log("Not")
});

React: Prevent click on scrollbar from propagating

I have a div that is scrollable unfortunately I also have event associated with onMouseDown on the div.
My problem is that when I want to scroll by clicking on the scrollbar those events are then fired.
Is there a way to make it so I can prevent the mouse event on the scrollbar from propagating ?
There doesn't seem to be a way to do this; not to my knowledge anyway.
However, there is one half-decent solution:
If you click on the scrollbar, the cursor coordinates is equal to the width of your element, in which case you can just return and prevent the event handler from doing its stuff.
Here, I have added an extra 7 pixels to the logic, to account for the width of the scrollbar on Chrome.v.58/MacOS. The width of the scrollbar is determined by browser through, so that value might need a slight tweak.
class MyApp extends React.Component {
divMouseDown(e) {
if((e.clientX + 7) >= e.target.clientWidth) return;
console.log("do stuff on click");
}
render() {
return (
<div id="my-div" onMouseDown={this.divMouseDown}>
<p>foo</p>
<p>bar</p>
<p>baz</p>
</div>
);
}
}
ReactDOM.render(<MyApp />, document.getElementById("myApp"));
#my-div {
background: beige;
height: 60px;
overflow: auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="myApp"></div>
I had the same problem. I had a div element, with another scrollable div inside of it. I wanted the onclick event to fire on both the outside and inside div, but not on the scrollbar.
The problem is that the scrollbar gets the mousedown as well.
The clean solution to prevent the mousedown on the scrollbar is to create a div that contains the scrollable content inside the div that contains the scrollbar. Then, we disable our onmousedown function when the target is the div with the scrollbar. Maybe it is clearer with an example:
document.onmousedown = function(e){
if(e.target.id != 'scroll'){
console.log('mousedown');
}
}
#outside {
position: relative;
width: 300px;
height: 200px;
background-color: green;
}
#scroll {
position: relative;
top: 10px;
left: 10px;
background-color: red;
width: 280px;
height: 100px;
overflow-y: scroll;
}
<div id='outside'>
<div id='scroll'>
<div id='container'>
foo<br>
bar<br>
eee<br>
foo<br>
bar<br>
eee<br>
foo<br>
bar<br>
eee<br>
</div>
</div>
</div>
The solution works because the 'scroll' div contains the scrollbar, but the 'container' div does not (you can see this really well if you inspect element). The only time the mousedown event's direct target is the 'scroll' div is when we are clicking on the scrollbar. Any clicks on the scrollbar are stopped, but everything else triggers the event.
Hope this helps.
Then put this on your onMouseDown function:
function myFunction(event, element) {
// Your code for div
// ...
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
}
And your div should be something like this:
<div onmousedown="myFunction(event, this);">Click me!</div>

JS/jQuery - set scroll bar of side nav bar to certain position

I have a side nav bar which looks like this:
.scroll-box {
overflow: hidden;
width: 128px;
}
.filler {
height: 256px;
overflow-y: auto;
}
.selector {
background-color: #369;
padding: 8px 4px;
text-align: center;
flex-grow: 1;
display: inline-block;
cursor: pointer;
box-sizing: border-box;
transition: .1s !important;
}
.bar {
height: 8px;
width: 100%;
background-color: #808080;
}
.label {
padding: 4px 8px;
background-color: #707070;
}
.active {
background-color: lightgrey;
color: #369;
}
<div class="scroll-box">
<div class="label">Dates</div>
<div class="filler">
<div class="selector">4-Aug-16</div>
<div class="selector">4-Aug-16</div>
<div class="selector">4-Aug-16</div>
<div class="selector">4-Aug-16</div>
<div class="selector">4-Aug-16</div>
<div class="selector">4-Aug-16</div>
<div class="selector">4-Aug-16</div>
<div class="selector">4-Aug-16</div>
<div class="selector active" id="today">15-Aug-16</div>
<div class="selector">4-Aug-16</div>
<div class="selector">4-Aug-16</div>
<div class="selector">4-Aug-16</div>
<div class="selector">4-Aug-16</div>
<div class="selector">4-Aug-16</div>
<div class="selector">4-Aug-16</div>
<div class="selector">4-Aug-16</div>
<div class="selector">4-Aug-16</div>
</div>
<div class="bar"></div>
</div>
I want to get it so that when the page loads, it automatically centers the view of the side nav bar to the today id element. I've tried putting myUrl#today but that changes the entire page scroll, which I do not want. I
I only want the scroll in the side nav bar to change it's position and center on the #today bit. Does anyone know of a way to do this?
I am willing to use jQuery and JS as well.
Thank you.
I think you can use jQuery code such as
$(document).ready(function(){
// when document is ready
// first check if #today is defined in HTML
// the $('') is the jQuery selector of to select an element
// $('#today') means select an element with the ID "today"
// the .length attribute is default javascript attribute to check
// how many of elements selected has existed
if($('#today').length > 0){
// the offset() function is a jQuery function that is used for check the
// relative distance from the border of current element to its parent
var distance_to_top = $('#today').offset().top;
var top_label_height = $('.label').height();
var distance_to_scroll = distance_to_top - top_label_height - 8;
// 8 px is body margin on jsfiddle
// scrollTop() function is another jQuery function to scroll an
// overflow element
$('.filler').scrollTop(distance_to_scroll);
}
});
find the offset of the today element relative to its parent, then minus the label height because the label will cover on top of the #today. the scroll to top
The demo can be found at here
Maybe this can do. (I can't test it right now...).
Basically, we get every element of the div that doesn't have the id "today" and we add the height of those elements. When we finally reach "today", we set the scrollbar to the height of every past elements added together and go out of the loop.
$(document).ready(function(){
var height = 0;
$(".filler *").each(function () {
if($(this).is("#today"))
{
return false; //to get out of the .each
}
else
{
height += $(this).height();
}
})
$( "div.demo" ).scrollTop(height); //set the scrollbar
});

Only target parent with event.target?

HTML:
<div onclick="doSomething()" id="parent">
<div id="child"></div>
</div>
CSS:
#parent {
background-color: blue;
width: 100%;
height: 100px;
}
#child {
background-color: green;
width: 50%;
height: inherit;
}
.myClass {
background-color: red !important;
}
JS:
function doSomething() {
event.target.className = ('myClass');
}
As you can see in this JSFIDDLE, upon clicking the child, instead of applying the class to the parent which triggers the function, it applies it to the child. I want to know how to avoid this and apply it to the parent no matter where I click inside of it. I am trying to avoid using the document.getElement(s)ByClass/Id method.Any help?
You can refer to the element that handles the event with currentTarget.
Identifies the current target for the event, as the event traverses the DOM. It always refers to the element the event handler has been attached to as opposed to event.target which identifies the element on which the event occurred.
However, instead of relying on the browser to provide a global event object, I would pass it to the function:
onclick="doSomething(event)"
You can also refer to the element the handler is bound to with this:
onclick="doSomething(event, this)"
Of course please consider to not use inline event handlers.
Just reference the target in your javascript call:
function doSomething(target) {
target.className = ('myClass');
}
#parent {
background-color: blue;
width: 100%;
height: 100px;
}
#child {
background-color: green;
width: 50%;
height: inherit;
}
.myClass {
background-color: red !important;
}
<div onclick="doSomething(this)" id="parent">
<div id="child"></div>
</div>
To get the immediate parent element of the clicked element you can use the 'path' array of the event. Path provides an array which includes every element in ascending order from the element you clicked to the top of the DOM.
Having trouble working out the exact browser support for this though.
var children = document.querySelectorAll('[id^="child-"]'),
clickEvent = function(event) {
console.log(event.path[0]); //prints clicked child element
console.log(event.path[1]); //prints parent
event.path[1].classList.toggle('row'); //toggles row or column mode of parent
event.path[0].classList.toggle('selected'); //toggles color of child
};
children.forEach(function(child) {
child.addEventListener('click', clickEvent);
});
<div id="parent">
<div id="child-1">Child One</div>
<div id="child-2">Child Two</div>
<div id="child-3">Child Three</div>
<div id="child-4">Child Four</div>
<div id="child-5">Child Five</div>
</div>

Toggle display:none with div in front of another div?

I'm trying to make a div that I have on top of another div show up when you click on something.
This is the code for the two divs, without all the stuff that's within each:
<div id="randomarticle_enlarge">
<h1></h1>
<h4></h4>
<p></p>
<p></p>
</div>
<div class="bodybag">
<h1></h1>
<h4></h4>
<p></p>
<p></p>
</div>
Then I have css for each, of course:
.bodybag {
width:960px;
}
#randomarticle_englarge {
height:750px;
width:960px;
position:absolute;
z-index:2;
margin-top:1px;
padding-left:20px;
padding-right:20px;
display: none;
}
Am I supposed to have the bodybag class have a z-index and a position:relative? Because even though I don't it's working (at this point).
Anyway, I have this script written that's doing exactly what I want it to do:
$(document).ready(function() {
$('.popular').click(function() {
$('#textmask').fadeTo( 'fast', 0.1);
$('#backgroundmask').css('background-color', 'white');
});
});
And all I want to happen next is that as the textmask and the backgroundmask fade in/change as they should and do, is for the randomarticle_enlarge div to show up.
I've tried using .toggle and .toggleClass and .slideToggle and .show but nothing is working.
Absolute positioning must be relative to a container. In order to absolutely position something you need to indicate what it's absolutely positioned to. Something along these lines.
<div id="randomarticle_englargeContainer">
<div id="randomarticle_englarge">
</div>
<div class="bodybag">
</div>
</div>
#randomarticle_englargeContainer {
position: relative;
}
.bodybag {
position: absolute;
left: 0;
top: 0;
}
When copying everything from above I have no issues using $('#randomarticle_englarge').toggle();. Check your browser's console for errors; you might find the answers there.
I'm not exactly sure about what would you like to do with the divs, but I created an example for you, maybe this is what you want:
LIVE DEMO
So there is two divs. The 2nd div covers the 1st one. Clicking on a 'button' hides the 2nd div, so the 1st one reveals. Clicking again the 'button', the 2nd div appears and covers the 1st one again.
HTML:
<div class="popular">Click me!</div>
<div class="container">
<div id="randomarticle_enlarge">
<h1>A</h1>
<h4>B</h4>
<p>C</p>
<p>D</p>
</div>
<div class="bodybag">
<h1>E</h1>
<h4>F</h4>
<p>G</p>
<p>H</p>
</div>
</div>
CSS:
.container {
position: relative;
}
.bodybag {
width: 100px;
height: 200px;
background-color: red;
}
#randomarticle_enlarge {
width: 100px;
height: 200px;
background-color: green;
position: absolute;
top: 0;
left: 0;
}
.hide {
display: none;
}
jQuery:
$(document).ready(function() {
$('.popular').click(function() {
$('#randomarticle_enlarge').toggleClass('hide');
});
});

Categories

Resources