Check parent element for valid DOM page - javascript

I have some HTML elements which I want to validate whether they fit within their parent elements width. Basically, I dont want any of the child container elements to exceed the parent elements width. for example:
<div id="parent" style="width:100px;">
<div id="child" style="width:120px;"> //wrong
</div>
with a large html page and multiple developers working, if a new element is added which violates this rule, the page alignment collapse. is there an js where i can tell validate this child element, and run the page on DOM, to check if the element succeeds this test

You shouldn't use javascript for it. The best solution is a good CSS pattern for your project.
But yes, you can validade the objects.
Something like this:
function validateParent(element, prop, callback) {
var parentProp = element.parentElement.style[prop];
var childProp = element.style[prop];
if(parseFloat(childProp) > parseFloat(parentProp)) {
// do something here like execute the callback
if(typeof callback === 'function') {
callback.call(element, prop, parentProp);
}
}
}
Using example:
// make the children value equals the parent
validateParent(document.getElementById('foo'), 'width', function(prop, val) {
this.style[prop] = val;
});
// Dispatch an alert
validateParent(document.getElementById('foo'), 'width', function(prop, val) {
alert('The value from ' + this.id + ' is bigger then it parent, that is ' + val;
});

Related

getting the item under the cursor when the cursor is clicked in google chrome [duplicate]

I want a function that tells me which element the mouse cursor is over.
So, for example, if the user's mouse is over this textarea (with id wmd-input), calling window.which_element_is_the_mouse_on() will be functionally equivalent to $("#wmd-input").
DEMO
There's a really cool function called document.elementFromPoint which does what it sounds like.
What we need is to find the x and y coords of the mouse and then call it using those values:
document.addEventListener('mousemove', e => {
console.clear()
console.log( document.elementFromPoint(e.clientX, e.clientY) )
}, {passive: true})
[class^='level']{
width: 100px;
height: 100px;
padding: 15px;
background: #00000033;
}
<div class='level-1'>
<div class='level-2'>
<div class='level-3'>
Hover
</div>
</div>
</div>
document.elementFromPoint
jQuery event object
In newer browsers, you could do the following:
document.querySelectorAll( ":hover" );
That'll give you a NodeList of items that the mouse is currently over in document order. The last element in the NodeList is the most specific, each preceding one should be a parent, grandparent, and so on.
Although the following may not actually answering the question, since this is the first result of googling (the googler may not asking exactly the same question:), hope it will provide some extra input.
There are actually two different approaches to get a list of all elements the mouse is currently over (for newer browsers, perhaps):
The "structural" approach - Ascending DOM tree
As in dherman's answer, one can call
var elements = document.querySelectorAll(':hover');
However, this assumes that only children will overlay their ancestors, which is usually the case, but not true in general, especially when dealing with SVG where element in different branches of the DOM tree may overlap each other.
The "visual" approach - Based on "visual" overlapping
This method uses document.elementFromPoint(x, y) to find the topmost element, temporarily hide it (since we recover it immediately in the same context, the browser will not actually renders this), then go on to find the second topmost element... Looks a little hacky, but it returns what you expect when there are, e.g., siblings elements in a tree occluding each other. Please find this post for more details,
function allElementsFromPoint(x, y) {
var element, elements = [];
var old_visibility = [];
while (true) {
element = document.elementFromPoint(x, y);
if (!element || element === document.documentElement) {
break;
}
elements.push(element);
old_visibility.push(element.style.visibility);
element.style.visibility = 'hidden'; // Temporarily hide the element (without changing the layout)
}
for (var k = 0; k < elements.length; k++) {
elements[k].style.visibility = old_visibility[k];
}
elements.reverse();
return elements;
}
Try both, and check their different returns.
elementFromPoint() gets only the first element in DOM tree. This is mostly not enough for developers needs. To get more than one element at e.g. the current mouse pointer position, this is the function you need:
document.elementsFromPoint(x, y) . // Mind the 's' in elements
This returns an array of all element objects under the given point.
Just pass the mouse X and Y values to this function.
More information is here: DocumentOrShadowRoot.elementsFromPoint()
For very old browsers which are not supported, you may use this answer as a fallback.
The following code will help you to get the element of the mouse pointer. The resulted elements will display in the console.
document.addEventListener('mousemove', function(e) {
console.log(document.elementFromPoint(e.pageX, e.pageY));
})
Mouseover events bubble, so you can put a single listener on the body and wait for them to bubble up, then grab the event.target or event.srcElement:
function getTarget(event) {
var el = event.target || event.srcElement;
return el.nodeType == 1? el : el.parentNode;
}
<body onmouseover="doSomething(getTarget(event));">
You can look at the target of the mouseover event on some suitable ancestor:
var currentElement = null;
document.addEventListener('mouseover', function (e) {
currentElement = e.target;
});
Here’s a demo.
Demo :D
Move your mouse in the snippet window :D
<script>
document.addEventListener('mouseover', function (e) {
console.log ("You are in ", e.target.tagName);
});
</script>
<!-- One simple solution to your problem could be like this: -->
<div>
<input type="text" id="fname" onmousemove="javascript: alert(this.id);" />
<!-- OR -->
<input type="text" id="fname" onclick="javascript: alert(this.id);" />
</div>
<!-- Both mousemove over the field & click on the field displays "fname"-->
<!-- Works fantastic in IE, FireFox, Chrome, Opera. -->
<!-- I didn't test it for Safari. -->
You can use this selector to undermouse object and then manipulate it as a jQuery object:
$(':hover').last();
2022 Update:
document.elementsFromPoint() (Note the 's' in elements) is compatible with all major browsers. It basically does the same thing that elementFrompoint does, but retrieves all the elements in DOM order.
Mozilla has a good example of this:
HTML
<div>
<p>Some text</p>
</div>
<p>Elements at point 30, 20:</p>
<div id="output"></div>
JavaScript
let output = document.getElementById("output");
if (document.elementsFromPoint) {
let elements = document.elementsFromPoint(30, 20);
for (var i = 0; i < elements.length; i++) {
output.textContent += elements[i].localName;
if (i < elements.length - 1) {
output.textContent += " < ";
}
}
} else {
output.innerHTML = "<span style=\"color: red;\">" +
"Browser does not support <code>document.elementsFromPoint()</code>" +
"</span>";
}
Output
Some text
Elements at point 30, 20:
p < div < body < html
https://developer.mozilla.org/en-US/docs/Web/API/Document/elementsFromPoint
The target of the mousemove DOM event is the top-most DOM element under the cursor when the mouse moves:
(function(){
//Don't fire multiple times in a row for the same element
var prevTarget=null;
document.addEventListener('mousemove', function(e) {
//This will be the top-most DOM element under cursor
var target=e.target;
if(target!==prevTarget){
console.log(target);
prevTarget=target;
}
});
})();
This is similar to #Philip Walton's solution, but doesn't require jQuery or a setInterval.
Here's a solution for those that may still be struggling. You want to add a mouseover event on the 'parent' element of the child element(s) you want detected. The below code shows you how to go about it.
const wrapper = document.getElementById('wrapper') //parent element
const position = document.getElementById("displaySelection")
wrapper.addEventListener('mousemove', function(e) {
let elementPointed = document.elementFromPoint(e.clientX, e.clientY)
console.log(elementPointed)
});
Demo on CodePen
Let me start out by saying that I don't recommend using the method I'm about to suggest. It's much better to use event driven development and bind events only to the elements you're interested in knowing whether or not the mouse is over with mouseover, mouseout, mouseenter, mouseleave, etc.
If you absolutely must have the ability to know which element the mouse is over, you'd need to write a function that binds the mouseover event to everything in the DOM, and then store whatever the current element is in some variable.
You could so something like this:
window.which_element_is_the_mouse_on = (function() {
var currentElement;
$("body *").on('mouseover', function(e) {
if(e.target === e.currentTarget) {
currentElement = this;
}
});
return function() {
console.log(currentElement);
}
}());
Basically, I've created an immediate function which sets the event on all elements and stores the current element within the closure to minimize your footprint.
Here's a working demo that calls window.which_element_is_the_mouse_on every second and logs what element the mouse is currently over to the console.
http://jsfiddle.net/LWFpJ/1/

Highlight div if child element name matches location.hash

I'm in an AngularJS web project.
I would like to highlight a div when clicking on an anchor link. The structure is as follows:
<div interaction-list-item="" sfinx-interaction="interaction" class="ng-isolate-scope">
...
<a name="iid_7923"></a>
...
</div>
And the anchor link sets the location.hash to the similar upon clicking, so a URL could look like this: http://localhost:9000/#/home#iid_7923. This iid_ is dynamic, with different id's after the _
I've tried several jQuery solutions that ends up with really ugly and long code:
$(".indicator.active.line-D").click(function () {
// more similar code..
if ($("div:contains('D4')") && $("a:contains('D4')")) {
$(".col-md-6.interactionscol:contains('D4')").css("border", "3px solid #428bca");
setTimeout(function () {
$(".col-md-6.interactionscol:contains('D4')").css("border", "");
}, 1000);
}
// more similar code..
});
The purpose of this snippet is that upon clicking the anchor lnik, check for the div and anchor matching eachother and then apply CSS onto it, removing it after 1 second.
How could I do this smarter - if location.hash contains for example #iid_7923 and the div with a tag which name has the same, highlight it!
I just can't figure it out. Thanks in advance.
UPDATE: I would like to achieve similar to this: target selector
But my code for the anchor is not similar to the classical way.. it looks like this:
$scope.scrollToInteraction = function (iid) {
$location.hash(iid);
$anchorScroll();
};
Using angular, make your hash public in either a controller or for the whole application using the $rootScope:
angular.module('foo').run(['$location', '$rootScope', function($location, $rootScope) {
$rootScope.currentHash = function() {
return $location.hash();
};
}]);
And then in your html just use a directive to style your div:
<div data-ng-class="{'active': currentHash() == 'iid_7923'}">
Note the missing # in your currentHash().
You can use the onhashchange event to add a class to the parent element.
var lastParent = null;
window.addEventListener('hashchange', function() {
// Remove class from previous target parent
if(lastParent)
{
lastParent.className = (' '+lastParent.className+' ').replace(' hastarget ',' ');
lastParent = null;
}
// Remove the '#' from the location hash
var targetId = document.location.hash.substr(1);
var target = document.getElementById(targetId);
// Try to support the name attribute
if(!target)
{
var nameTargets = document.getElementsByName(targetId);
// If nothing found, don't do anything
if(nameTargets.length == 0) return;
target = nameTargets[0];
}
// If the element does not have any parent, add the class to the <html> tag
lastParent = target.parentElement || document.documentElement;
lastParent.className += ' hastarget';
}, false);
JSFiddle demo

How to get DOM or jQuery element by mouse coordinates? [duplicate]

I want a function that tells me which element the mouse cursor is over.
So, for example, if the user's mouse is over this textarea (with id wmd-input), calling window.which_element_is_the_mouse_on() will be functionally equivalent to $("#wmd-input").
DEMO
There's a really cool function called document.elementFromPoint which does what it sounds like.
What we need is to find the x and y coords of the mouse and then call it using those values:
document.addEventListener('mousemove', e => {
console.clear()
console.log( document.elementFromPoint(e.clientX, e.clientY) )
}, {passive: true})
[class^='level']{
width: 100px;
height: 100px;
padding: 15px;
background: #00000033;
}
<div class='level-1'>
<div class='level-2'>
<div class='level-3'>
Hover
</div>
</div>
</div>
document.elementFromPoint
jQuery event object
In newer browsers, you could do the following:
document.querySelectorAll( ":hover" );
That'll give you a NodeList of items that the mouse is currently over in document order. The last element in the NodeList is the most specific, each preceding one should be a parent, grandparent, and so on.
Although the following may not actually answering the question, since this is the first result of googling (the googler may not asking exactly the same question:), hope it will provide some extra input.
There are actually two different approaches to get a list of all elements the mouse is currently over (for newer browsers, perhaps):
The "structural" approach - Ascending DOM tree
As in dherman's answer, one can call
var elements = document.querySelectorAll(':hover');
However, this assumes that only children will overlay their ancestors, which is usually the case, but not true in general, especially when dealing with SVG where element in different branches of the DOM tree may overlap each other.
The "visual" approach - Based on "visual" overlapping
This method uses document.elementFromPoint(x, y) to find the topmost element, temporarily hide it (since we recover it immediately in the same context, the browser will not actually renders this), then go on to find the second topmost element... Looks a little hacky, but it returns what you expect when there are, e.g., siblings elements in a tree occluding each other. Please find this post for more details,
function allElementsFromPoint(x, y) {
var element, elements = [];
var old_visibility = [];
while (true) {
element = document.elementFromPoint(x, y);
if (!element || element === document.documentElement) {
break;
}
elements.push(element);
old_visibility.push(element.style.visibility);
element.style.visibility = 'hidden'; // Temporarily hide the element (without changing the layout)
}
for (var k = 0; k < elements.length; k++) {
elements[k].style.visibility = old_visibility[k];
}
elements.reverse();
return elements;
}
Try both, and check their different returns.
elementFromPoint() gets only the first element in DOM tree. This is mostly not enough for developers needs. To get more than one element at e.g. the current mouse pointer position, this is the function you need:
document.elementsFromPoint(x, y) . // Mind the 's' in elements
This returns an array of all element objects under the given point.
Just pass the mouse X and Y values to this function.
More information is here: DocumentOrShadowRoot.elementsFromPoint()
For very old browsers which are not supported, you may use this answer as a fallback.
The following code will help you to get the element of the mouse pointer. The resulted elements will display in the console.
document.addEventListener('mousemove', function(e) {
console.log(document.elementFromPoint(e.pageX, e.pageY));
})
Mouseover events bubble, so you can put a single listener on the body and wait for them to bubble up, then grab the event.target or event.srcElement:
function getTarget(event) {
var el = event.target || event.srcElement;
return el.nodeType == 1? el : el.parentNode;
}
<body onmouseover="doSomething(getTarget(event));">
You can look at the target of the mouseover event on some suitable ancestor:
var currentElement = null;
document.addEventListener('mouseover', function (e) {
currentElement = e.target;
});
Here’s a demo.
Demo :D
Move your mouse in the snippet window :D
<script>
document.addEventListener('mouseover', function (e) {
console.log ("You are in ", e.target.tagName);
});
</script>
<!-- One simple solution to your problem could be like this: -->
<div>
<input type="text" id="fname" onmousemove="javascript: alert(this.id);" />
<!-- OR -->
<input type="text" id="fname" onclick="javascript: alert(this.id);" />
</div>
<!-- Both mousemove over the field & click on the field displays "fname"-->
<!-- Works fantastic in IE, FireFox, Chrome, Opera. -->
<!-- I didn't test it for Safari. -->
You can use this selector to undermouse object and then manipulate it as a jQuery object:
$(':hover').last();
2022 Update:
document.elementsFromPoint() (Note the 's' in elements) is compatible with all major browsers. It basically does the same thing that elementFrompoint does, but retrieves all the elements in DOM order.
Mozilla has a good example of this:
HTML
<div>
<p>Some text</p>
</div>
<p>Elements at point 30, 20:</p>
<div id="output"></div>
JavaScript
let output = document.getElementById("output");
if (document.elementsFromPoint) {
let elements = document.elementsFromPoint(30, 20);
for (var i = 0; i < elements.length; i++) {
output.textContent += elements[i].localName;
if (i < elements.length - 1) {
output.textContent += " < ";
}
}
} else {
output.innerHTML = "<span style=\"color: red;\">" +
"Browser does not support <code>document.elementsFromPoint()</code>" +
"</span>";
}
Output
Some text
Elements at point 30, 20:
p < div < body < html
https://developer.mozilla.org/en-US/docs/Web/API/Document/elementsFromPoint
The target of the mousemove DOM event is the top-most DOM element under the cursor when the mouse moves:
(function(){
//Don't fire multiple times in a row for the same element
var prevTarget=null;
document.addEventListener('mousemove', function(e) {
//This will be the top-most DOM element under cursor
var target=e.target;
if(target!==prevTarget){
console.log(target);
prevTarget=target;
}
});
})();
This is similar to #Philip Walton's solution, but doesn't require jQuery or a setInterval.
Here's a solution for those that may still be struggling. You want to add a mouseover event on the 'parent' element of the child element(s) you want detected. The below code shows you how to go about it.
const wrapper = document.getElementById('wrapper') //parent element
const position = document.getElementById("displaySelection")
wrapper.addEventListener('mousemove', function(e) {
let elementPointed = document.elementFromPoint(e.clientX, e.clientY)
console.log(elementPointed)
});
Demo on CodePen
Let me start out by saying that I don't recommend using the method I'm about to suggest. It's much better to use event driven development and bind events only to the elements you're interested in knowing whether or not the mouse is over with mouseover, mouseout, mouseenter, mouseleave, etc.
If you absolutely must have the ability to know which element the mouse is over, you'd need to write a function that binds the mouseover event to everything in the DOM, and then store whatever the current element is in some variable.
You could so something like this:
window.which_element_is_the_mouse_on = (function() {
var currentElement;
$("body *").on('mouseover', function(e) {
if(e.target === e.currentTarget) {
currentElement = this;
}
});
return function() {
console.log(currentElement);
}
}());
Basically, I've created an immediate function which sets the event on all elements and stores the current element within the closure to minimize your footprint.
Here's a working demo that calls window.which_element_is_the_mouse_on every second and logs what element the mouse is currently over to the console.
http://jsfiddle.net/LWFpJ/1/

jQuery function similar to closest that will return elements outside of the parent chain

Is there any jQuery function similar to closest() that will return elements outside of the parent chain, traversing sideways? For example, I want to call a function foo() on the div source that would return the div target. I know I could navigate using parent() and siblings(), but I need something generic that would go as many levels as needed, up, sideways and down?
var allsources = $('.source');
allsources.click(function()){
$(this).closest('.target').hide();
});
<div class="row">
<div>
<div class="target" ></div>
</div>
<div>
<div>
<div class="source"></div>
</div>
</div>
</div>
<div class="row">
<div>
<div class="target" ></div>
</div>
<div>
<div>
<div class="source"></div>
</div>
</div>
</div>
EDIT:
My definition of closest: you have an element source. Try to find it down. If find more than one, return one that is less node hoops down/next/prev. If not found, go one level up, and try to find again. Repeat until no parent.
If, by closest, you mean "travel up as little as possible, then anywhere downwards", then you can do
$("#source")
.closest(":has(.target)")
.find(".target:first") //make sure we only select one element in case of a tie
In your case, it would be better to specify the common parent directly:
$(this)
.closest(".row")
.find(".target") //there's no tie here, no need to arbitrate
This is a tricky one. As has been commented, how do you define closest in this context? Assuming you can decide on some rules; for example:
Traverse up: 3pt
Traverse down: 2pts
Move sideways: 1pts
And then consider the item with the lowest points to be "closest" then it would be easy enough to author a plugin, named something such as closestAll, which would do the recursive traversal of the whole dom tree to determine the closest item.
However, looking at your recent edit, one (of many!) right solutions to the problem stated is:
var allsources = $('.source');
allsources.click(function(){
$(this).parents('.row').find('.target').hide();
});
Live example: http://jsfiddle.net/zCvJM/ (Source A only hides Target A, Same for B)
If you know exactly the structure of the dom and level of nesting, have you consider to use the eq() method
$(this).parents().eq(1).prev().children(".target")
I don't think there is a way to do this other than basically querying the whole DOM:
$('#target')
Because if you want to go up and across (never mind down as well) then the target element isn't related to the child element. If you also want to check for the presence of the child element you will have to do that separately.
-Edit:
After reading your comment on wanting to find the closest element regardless of whether it is a parent, I think you will have to write a custom function to crawl back up the dom one node at a time. I have tested the following and it works:
Markup
<div id="parent">
<div id="child1">
<div id="source"></div>
</div>
<div id="child2">
<div class="target" rel="right"></div>
</div>
<div id="child3">
<div>
<div class="target" rel="wrong"></div>
</div>
</div>
</div>
Script
$(document).ready(function () {
var tgt = findClosest($('#source'), '.target');
if (tgt != undefined) {
alert(tgt.attr('rel'));
}
});
function findClosest(source, targetSel) {
var crawledNodes = $();
var target = null;
// Go up
source.parents().each(function () {
console.log(crawledNodes.index($(this)));
if (crawledNodes.index($(this)) == -1 && target == null) {
crawledNodes.add($(this));
target = findTarget($(this), targetSel);
// Go across
$(this).siblings().each(function () {
console.log("Sibling");
if (crawledNodes.index($(this)) == -1 && target == null) {
crawledNodes.add($(this));
target = findTarget($(this), targetSel);
}
});
}
});
return target;
}
function findTarget(el, targetSel) {
console.log(targetSel);
var target = el.find(targetSel);
if (target.size() > 0) {
return target.eq(0);
}
else
{
return null;
}
}
If I understood the specification correctly you mean something like the function closest defined below:
var allsources = $(".source");
function closest($source,selector) {
if($source == null) return $([]);
var $matchingChildren = $source.find(selector);
if($matchingChildren.length != 0) return $($matchingChildren.get(0));
else return closest($source.parent(), selector)
}
allsources.click(closest($(this),'.target').hide();});
You can see it working at http://jsfiddle.net/y2wJV/1/
Your definition requires that when choosing among matching children the function must return one that is less node hoops down/next/prev. This requirement has not been met, but this function is quite flexible and seems to do what you want to do in the case of the example you provided.
I found this code that is simple but does not solve the tie issue (returns the first)...
(function ($) {
$.fn.findClosest = function (filter) {
var $found = $(),
$currentSet = this; // Current place
while ($currentSet.length) {
$found = $currentSet.find(filter);
if ($found.length) break; // At least one match: break loop
// Get all children of the current set
$currentSet = $currentSet.parent();
}
return $found.first(); // Return first match of the collection
};
})(jQuery);
I encountered a similar problem, i had a table i needed to find the next element which may be outside the current td, so i made a jquery function:
$.fn.nextAllLevels = function(sel) {
if ($(this).nextAll(sel).length != 0) {
return $(this).nextAll(sel).eq(0);
} else if ($(this).nextAll(':has(' + sel + ')').length != 0) {
return $(this).nextAll(':has(' + sel + ')').find(sel).eq(0);
} else {
return $(this).parent().nextAllLevels(sel);
}
So to use this you simply call
$('#current').nextAllLevels('.target');
To give you the element closest in the foward direction, regardsless of whether in is in the current parent or not.

Determine which element the mouse pointer is on top of in JavaScript

I want a function that tells me which element the mouse cursor is over.
So, for example, if the user's mouse is over this textarea (with id wmd-input), calling window.which_element_is_the_mouse_on() will be functionally equivalent to $("#wmd-input").
DEMO
There's a really cool function called document.elementFromPoint which does what it sounds like.
What we need is to find the x and y coords of the mouse and then call it using those values:
document.addEventListener('mousemove', e => {
console.clear()
console.log( document.elementFromPoint(e.clientX, e.clientY) )
}, {passive: true})
[class^='level']{
width: 100px;
height: 100px;
padding: 15px;
background: #00000033;
}
<div class='level-1'>
<div class='level-2'>
<div class='level-3'>
Hover
</div>
</div>
</div>
document.elementFromPoint
jQuery event object
In newer browsers, you could do the following:
document.querySelectorAll( ":hover" );
That'll give you a NodeList of items that the mouse is currently over in document order. The last element in the NodeList is the most specific, each preceding one should be a parent, grandparent, and so on.
Although the following may not actually answering the question, since this is the first result of googling (the googler may not asking exactly the same question:), hope it will provide some extra input.
There are actually two different approaches to get a list of all elements the mouse is currently over (for newer browsers, perhaps):
The "structural" approach - Ascending DOM tree
As in dherman's answer, one can call
var elements = document.querySelectorAll(':hover');
However, this assumes that only children will overlay their ancestors, which is usually the case, but not true in general, especially when dealing with SVG where element in different branches of the DOM tree may overlap each other.
The "visual" approach - Based on "visual" overlapping
This method uses document.elementFromPoint(x, y) to find the topmost element, temporarily hide it (since we recover it immediately in the same context, the browser will not actually renders this), then go on to find the second topmost element... Looks a little hacky, but it returns what you expect when there are, e.g., siblings elements in a tree occluding each other. Please find this post for more details,
function allElementsFromPoint(x, y) {
var element, elements = [];
var old_visibility = [];
while (true) {
element = document.elementFromPoint(x, y);
if (!element || element === document.documentElement) {
break;
}
elements.push(element);
old_visibility.push(element.style.visibility);
element.style.visibility = 'hidden'; // Temporarily hide the element (without changing the layout)
}
for (var k = 0; k < elements.length; k++) {
elements[k].style.visibility = old_visibility[k];
}
elements.reverse();
return elements;
}
Try both, and check their different returns.
elementFromPoint() gets only the first element in DOM tree. This is mostly not enough for developers needs. To get more than one element at e.g. the current mouse pointer position, this is the function you need:
document.elementsFromPoint(x, y) . // Mind the 's' in elements
This returns an array of all element objects under the given point.
Just pass the mouse X and Y values to this function.
More information is here: DocumentOrShadowRoot.elementsFromPoint()
For very old browsers which are not supported, you may use this answer as a fallback.
The following code will help you to get the element of the mouse pointer. The resulted elements will display in the console.
document.addEventListener('mousemove', function(e) {
console.log(document.elementFromPoint(e.pageX, e.pageY));
})
Mouseover events bubble, so you can put a single listener on the body and wait for them to bubble up, then grab the event.target or event.srcElement:
function getTarget(event) {
var el = event.target || event.srcElement;
return el.nodeType == 1? el : el.parentNode;
}
<body onmouseover="doSomething(getTarget(event));">
You can look at the target of the mouseover event on some suitable ancestor:
var currentElement = null;
document.addEventListener('mouseover', function (e) {
currentElement = e.target;
});
Here’s a demo.
Demo :D
Move your mouse in the snippet window :D
<script>
document.addEventListener('mouseover', function (e) {
console.log ("You are in ", e.target.tagName);
});
</script>
<!-- One simple solution to your problem could be like this: -->
<div>
<input type="text" id="fname" onmousemove="javascript: alert(this.id);" />
<!-- OR -->
<input type="text" id="fname" onclick="javascript: alert(this.id);" />
</div>
<!-- Both mousemove over the field & click on the field displays "fname"-->
<!-- Works fantastic in IE, FireFox, Chrome, Opera. -->
<!-- I didn't test it for Safari. -->
You can use this selector to undermouse object and then manipulate it as a jQuery object:
$(':hover').last();
2022 Update:
document.elementsFromPoint() (Note the 's' in elements) is compatible with all major browsers. It basically does the same thing that elementFrompoint does, but retrieves all the elements in DOM order.
Mozilla has a good example of this:
HTML
<div>
<p>Some text</p>
</div>
<p>Elements at point 30, 20:</p>
<div id="output"></div>
JavaScript
let output = document.getElementById("output");
if (document.elementsFromPoint) {
let elements = document.elementsFromPoint(30, 20);
for (var i = 0; i < elements.length; i++) {
output.textContent += elements[i].localName;
if (i < elements.length - 1) {
output.textContent += " < ";
}
}
} else {
output.innerHTML = "<span style=\"color: red;\">" +
"Browser does not support <code>document.elementsFromPoint()</code>" +
"</span>";
}
Output
Some text
Elements at point 30, 20:
p < div < body < html
https://developer.mozilla.org/en-US/docs/Web/API/Document/elementsFromPoint
The target of the mousemove DOM event is the top-most DOM element under the cursor when the mouse moves:
(function(){
//Don't fire multiple times in a row for the same element
var prevTarget=null;
document.addEventListener('mousemove', function(e) {
//This will be the top-most DOM element under cursor
var target=e.target;
if(target!==prevTarget){
console.log(target);
prevTarget=target;
}
});
})();
This is similar to #Philip Walton's solution, but doesn't require jQuery or a setInterval.
Here's a solution for those that may still be struggling. You want to add a mouseover event on the 'parent' element of the child element(s) you want detected. The below code shows you how to go about it.
const wrapper = document.getElementById('wrapper') //parent element
const position = document.getElementById("displaySelection")
wrapper.addEventListener('mousemove', function(e) {
let elementPointed = document.elementFromPoint(e.clientX, e.clientY)
console.log(elementPointed)
});
Demo on CodePen
Let me start out by saying that I don't recommend using the method I'm about to suggest. It's much better to use event driven development and bind events only to the elements you're interested in knowing whether or not the mouse is over with mouseover, mouseout, mouseenter, mouseleave, etc.
If you absolutely must have the ability to know which element the mouse is over, you'd need to write a function that binds the mouseover event to everything in the DOM, and then store whatever the current element is in some variable.
You could so something like this:
window.which_element_is_the_mouse_on = (function() {
var currentElement;
$("body *").on('mouseover', function(e) {
if(e.target === e.currentTarget) {
currentElement = this;
}
});
return function() {
console.log(currentElement);
}
}());
Basically, I've created an immediate function which sets the event on all elements and stores the current element within the closure to minimize your footprint.
Here's a working demo that calls window.which_element_is_the_mouse_on every second and logs what element the mouse is currently over to the console.
http://jsfiddle.net/LWFpJ/1/

Categories