I want to apply a click event to an entire page in Javascript, to everything but a single banner on top. Let's say that the banner that I don't want the event in has an id of 'bannerID'. I tried doing the following:
document.onclick = function(){clickEvent()}
document.getElementById("bannerID").onclick = function(){return false;}
However, it looks like the document event overrides everything. Does anyone have any advice?
Check for the element-id within the handler, something like;
document.onclick = clickEvent;
function clickEvent(e) {
var from = e.target || e.srcElement;
if (from.id === 'bannerID') { return; }
/* ... the handling continues ... */
}
This is called event delegation
Pass in an event parameter to the callback and check if the id is 'bannerID'
document.onclick =
function(event){
if(event.target.id != 'bannerID'){
clickEvent()
}
};
demo
In the code you have above, you are adding two click events to "bannerID" - so it will execute clickEvent() and return false.
You can, however, exclude the specific element from the onclick function. This might help:
document.onclick = function(e) {
if (e.target.id === 'bannerID') {
return false;
} else {
clickEvent();
}
};
Related
I have searched for a good solution everywhere, yet I can't find one which does not use jQuery.
Is there a cross-browser, normal way (without weird hacks or easy to break code), to detect a click outside of an element (which may or may not have children)?
Add an event listener to document and use Node.contains() to find whether the target of the event (which is the inner-most clicked element) is inside your specified element. It works even in IE5
const specifiedElement = document.getElementById('a')
// I'm using "click" but it works with any event
document.addEventListener('click', event => {
const isClickInside = specifiedElement.contains(event.target)
if (!isClickInside) {
// The click was OUTSIDE the specifiedElement, do something
}
})
var specifiedElement = document.getElementById('a');
//I'm using "click" but it works with any event
document.addEventListener('click', function(event) {
var isClickInside = specifiedElement.contains(event.target);
if (isClickInside) {
alert('You clicked inside A')
} else {
alert('You clicked outside A')
}
});
div {
margin: auto;
padding: 1em;
max-width: 6em;
background: rgba(0, 0, 0, .2);
text-align: center;
}
Is the click inside A or outside?
<div id="a">A
<div id="b">B
<div id="c">C</div>
</div>
</div>
You need to handle the click event on document level. In the event object, you have a target property, the inner-most DOM element that was clicked. With this you check itself and walk up its parents until the document element, if one of them is your watched element.
See the example on jsFiddle
document.addEventListener("click", function (e) {
var level = 0;
for (var element = e.target; element; element = element.parentNode) {
if (element.id === 'x') {
document.getElementById("out").innerHTML = (level ? "inner " : "") + "x clicked";
return;
}
level++;
}
document.getElementById("out").innerHTML = "not x clicked";
});
As always, this isn't cross-bad-browser compatible because of addEventListener/attachEvent, but it works like this.
A child is clicked, when not event.target, but one of it's parents is the watched element (i'm simply counting level for this). You may also have a boolean var, if the element is found or not, to not return the handler from inside the for clause. My example is limiting to that the handler only finishes, when nothing matches.
Adding cross-browser compatability, I'm usually doing it like this:
var addEvent = function (element, eventName, fn, useCapture) {
if (element.addEventListener) {
element.addEventListener(eventName, fn, useCapture);
}
else if (element.attachEvent) {
element.attachEvent(eventName, function (e) {
fn.apply(element, arguments);
}, useCapture);
}
};
This is cross-browser compatible code for attaching an event listener/handler, inclusive rewriting this in IE, to be the element, as like jQuery does for its event handlers. There are plenty of arguments to have some bits of jQuery in mind ;)
How about this:
jsBin demo
document.onclick = function(event){
var hasParent = false;
for(var node = event.target; node != document.body; node = node.parentNode)
{
if(node.id == 'div1'){
hasParent = true;
break;
}
}
if(hasParent)
alert('inside');
else
alert('outside');
}
you can use composePath() to check if the click happened outside or inside of a target div that may or may not have children:
const targetDiv = document.querySelector('#targetDiv')
document.addEventListener('click', (e) => {
const isClickedInsideDiv = e.composedPath().includes(targetDiv)
if (isClickedInsideDiv) {
console.log('clicked inside of div')
} else {
console.log('clicked outside of div')
}
})
I did a lot of research on it to find a better method. JavaScript method .contains go recursively in DOM to check whether it contains target or not. I used it in one of react project but when react DOM changes on set state, .contains method does not work. SO i came up with this solution
//Basic Html snippet
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="mydiv">
<h2>
click outside this div to test
</h2>
Check click outside
</div>
</body>
</html>
//Implementation in Vanilla javaScript
const node = document.getElementById('mydiv')
//minor css to make div more obvious
node.style.width = '300px'
node.style.height = '100px'
node.style.background = 'red'
let isCursorInside = false
//Attach mouseover event listener and update in variable
node.addEventListener('mouseover', function() {
isCursorInside = true
console.log('cursor inside')
})
/Attach mouseout event listener and update in variable
node.addEventListener('mouseout', function() {
isCursorInside = false
console.log('cursor outside')
})
document.addEventListener('click', function() {
//And if isCursorInside = false it means cursor is outside
if(!isCursorInside) {
alert('Outside div click detected')
}
})
WORKING DEMO jsfiddle
using the js Element.closest() method:
let popup = document.querySelector('.parent-element')
popup.addEventListener('click', (e) => {
if (!e.target.closest('.child-element')) {
// clicked outside
}
});
To hide element by click outside of it I usually apply such simple code:
var bodyTag = document.getElementsByTagName('body');
var element = document.getElementById('element');
function clickedOrNot(e) {
if (e.target !== element) {
// action in the case of click outside
bodyTag[0].removeEventListener('click', clickedOrNot, true);
}
}
bodyTag[0].addEventListener('click', clickedOrNot, true);
Another very simple and quick approach to this problem is to map the array of path into the event object returned by the listener. If the id or class name of your element matches one of those in the array, the click is inside your element.
(This solution can be useful if you don't want to get the element directly (e.g: document.getElementById('...'), for example in a reactjs/nextjs app, in ssr..).
Here is an example:
document.addEventListener('click', e => {
let clickedOutside = true;
e.path.forEach(item => {
if (!clickedOutside)
return;
if (item.className === 'your-element-class')
clickedOutside = false;
});
if (clickedOutside)
// Make an action if it's clicked outside..
});
I hope this answer will help you !
(Let me know if my solution is not a good solution or if you see something to improve.)
I am thinking of to add a javascript function to capture all the <a> click events inside a html page.
So I am adding a global function that governs all the <a> click events, but not adding onclick to each (neither using .onclick= nor attachEvent(onclick...) nor inline onclick=). I will leave each <a> as simple as <a href="someurl"> within the html without touching them.
I tried window.onclick = function (e) {...}
but that just captures all the clicks
How do I specify only the clicks on <a> and to extract the links inside <a> that is being clicked?
Restriction: I don't want to use any exra libraries like jQuery, just vanilla javascript.
Use event delegation:
document.addEventListener(`click`, e => {
const origin = e.target.closest(`a`);
if (origin) {
console.clear();
console.log(`You clicked ${origin.href}`);
}
});
<div>
some link
<div><div><i>some other (nested) link</i></div></div>
</div>
[edit 2020/08/20] Modernized
You can handle all click using window.onclick and then filter using event.target
Example as you asked:
<html>
<head>
<script type="text/javascript">
window.onclick = function(e) { alert(e.target);};
</script>
</head>
<body>
google
yahoo
facebook
</body>
</html>
window.onclick = function (e) {
if (e.target.localName == 'a') {
console.log('a tag clicked!');
}
}
The working demo.
your idea to delegate the event to the window and then check if the "event.target" is a link, is one way to go (better would be document.body). The trouble here is that it won't work if you click on a child node of your element. Think:
<b>I am bold</b>
the target would be the <b> element, not the link. This means checking for e.target won't work. So, you would have to crawl up all the dom tree to check if the clicked element is a descendant of a <a> element.
Another method that requires less computation on every click, but costs more to initialize would be to get all <a> tags and attach your event in a loop:
var links = Array.prototype.slice.call(
document.getElementsByTagName('a')
);
var count = links.length;
for(var i = 0; i < count; i++) {
links[i].addEventListener('click', function(e) {
//your code here
});
}
(PS: why do I convert the HTMLCollection to array? here's the answer.)
You need to take into account that a link can be nested with other elements and want to traverse the tree back to the 'a' element. This works for me:
window.onclick = function(e) {
var node = e.target;
while (node != undefined && node.localName != 'a') {
node = node.parentNode;
}
if (node != undefined) {
console.log(node.href);
/* Your link handler here */
return false; // stop handling the click
} else {
return true; // handle other clicks
}
}
See e.g. https://jsfiddle.net/hnmdijkema/nn5akf3b/6/
You can also try using this:
var forEach = Array.prototype.forEach;
var links = document.getElementsByTagName('a');
forEach.call(links, function (link) {
link.onclick = function () {
console.log('Clicked');
}
});
It works, I just tested!
Working Demo: http://jsfiddle.net/CR7Sz/
Somewhere in comments you mentioned you want to get the 'href' value you can do that with this:
var forEach = Array.prototype.forEach;
var links = document.getElementsByTagName('a');
forEach.call(links, function (link) {
link.onclick = function () {
console.log(link.href); //use link.href for the value
}
});
Demo: http://jsfiddle.net/CR7Sz/1/
Try jQuery and
$('a').click(function(event) { *your code here* });
In this function you can extract href value in this way:
$(this).attr('href')
Some accepted answers dont work with nested elements like:
<font><u>link</u></font>
There is a basic solution for most cases:
```
var links = document.getElementsByTagName('a');
for(var i in links)
{
links[i].onclick = function(e){
e.preventDefault();
var href = this.href;
// ... do what you need here.
}
}
If anybody is looking for the typed version (TypeScript, using Kooilnc's answer), here it is:
document.addEventListener("click", (e: Event) => {
if(!e.target) { return; }
if(!(e.target instanceof Element)) { return; }
const origin = e.target.closest("a");
if(!origin || !origin.href) { return; }
console.log(`You clicked ${origin.href}`);
});
I guess this simple code will work with jquery.
$("a").click(function(){
alert($(this).attr('href'));
});
Without JQuery:
window.onclick = function(e) {
if(e.target.localName=='a')
alert(e.target);
};
The above will produce the same result.
Very simple :
document.getElementById("YOUR_ID").onclick = function (e) {...}
The selector is what you want to select so lets say you have button called
Button1
The code to capure this is:
document.getElementById("button1").onclick = function (e) { alert('button1 clicked'); }
Hope that helps.
I want to detect in my firefox extension if a link has been clicked. So far, for this I add a click event listener to the window
window.addEventListener("click", function(event) { handleWindowClick(event); }, false);
...
handleWindowClick : function(event) {
if ("event.target is a link") {
// do something
}
};
For some links the event.target is simple the URL. However, for some links I get, e.g., a HTMLSpanElement as event.target. Am I on the right track to catch link clicks or are there other ways? If it works this way, how can I ensure the successfully test if the event.targer is a link?
You're adding an event listener to the main window which registers any click. The url's you're having problems with must be wrapped in a <span> tag. What you need is event delegation
Why don't you just put the click event listener to anchors (<a>)?
var hrefs = document.getElementsByTagName('a');
for (i = 0; i < hrefs.length; i++) {
hrefs[i].addEventListener(...)
...
}
or in jQuery:
$('a').click(function () {
...
});
check this out, i hope this is what you are looking for.
window.addEventListener("click", function(event) {
handleWindowClick(event);
}, false);
function handleWindowClick(event){
var origEl = event.target || event.srcElement;
if(origEl.tagName === 'A')
alert("anchor link is clicked");
else if(origEl.parentNode.tagName === 'A')
alert("clicked inside anchor");
else if(origEl.tagName === 'SPAN')
alert("span is clicked");
}
fiddle : http://jsfiddle.net/5zXkN/3/
I extended the answer of dku.rajkumar to support arbitrary constructs within "A"-tags. I'm simply go up the tree until I either find an "A" or I'm at the root (so no link clicked in this case). It seems to do the trick. Thanks to all for your help!
window.addEventListener("click", function(event) { handleWindowClick(event); }, false);
...
isLink : function(element) {
if(element.tagName === 'A')
return true;
else
if (element.parentNode)
return this.isLink(element.parentNode)
else
return false;
},
handleWindowClick : function(event) {
var element = event.target || event.srcElement;
var isLink = this.isLink(element);
if (isLink)
dump("A link has been clicked.\n");
},
Can somebody tell me what I am doing wrong?
window.onload = initForm;
function initForm() {
var allTags = document.getElementsByTagName("*");
for(i=0; i<allTags.length; i++) {
if (allTags[i].className.indexOf("textbox") > -1) {
allTags[i].onFocus = fieldSelect;
allTags[i].onBlur = fieldDeSelect;
}
}
}
function fieldSelect() {
this.style.backgroundImage = "url('inputBackSelected.png')";
}
function fieldDeSelect() {
this.style.backgroundImage = "url('inputBack.png')";
}
I am a beginner at JavaScript so I am not used to debugging code yet.
Thanks
Luke
Your problem lies in attaching your event handlers. You should bind to onfocus and onblur (note the lowercase event name).
As a suggestion, you may want to look at a very simple cross browser addEvent() with a quick line of code added to ensure the proper this pointer:
function addEvent(obj, evType, fn, useCapture){
if (obj.addEventListener){
obj.addEventListener(evType, fn, useCapture);
return true;
} else if (obj.attachEvent){
// fix added by me to handle the `this` issue
var r = obj.attachEvent("on"+evType, function(){
retrun fn.apply(obj, arguments);
});
return r;
} else {
alert("Handler could not be attached");
}
}
And then use the addEvent function instead of allTags[i].onfocus = you will probably have better mileage in the future binding events.
addEvent(allTags[i], 'focus', fieldSelect);
addEvent(allTags[i], 'blur', fieldDeSelect);
jsfiddle demonstration
The problem is that when fieldSelect and fieldDeselect are getting called, this refers to the window object, not to the element that fired the event. You might want to consider using jQuery:
$(document).ready(function() {
$('.textbox').focus(fieldSelect).blur(fieldDeselect);
});
function fieldSelect() {
$(this).css('background-image', 'url("inputBackSelected.png")');
}
function fieldDeselect() {
$(this).css('background-image', 'url("inputBack.png")');
}
jQuery takes care of making sure that when your event handlers are getting called, this refers to the element that fired the event.
Two things, the events should be all lower case (onfocus, onblur) and this doesn't point to the object that triggered the event in IE. Try this:
function fieldSelect(e) {
var event;
if(!e) {
event = window.event;
} else {
event = e;
}
event.target.style.backgroundImage = "url('inputBackSelected.png')";
}
function fieldDeSelect(e) {
var event;
if(!e) {
event = window.event;
} else {
event = e;
}
event.target.style.backgroundImage = "url('inputBack.png')";
}
Standards complient browsers will pass an event object to the event handler. IE uses a global window.event object instead. Either way you can use that object to get the target of the event that triggered the handler.
Another, probably preferable option would be to have your functions set and remove a className instead of directly changing the style. Then put a style called maybe selected in your stylesheet that overrides the background image. That way you keep style info and behavior separate.
Instead of window.onload=initform try window.onload=function(){/the init function/}
Also when refering to a function you should use () even if there are no arguments.
Is this possible?
I am attempting to write a function for onmousedown that will return the ID of the element you just clicked for later use in recreating that element in a different div.
You can use event delegation, to basically connect only one event handler to your entire document, and get the element which the event was originally dispatched, using event.target:
document.body.onmousedown = function (e) {
e = e || window.event;
var elementId = (e.target || e.srcElement).id;
// call your re-create function
recreate(elementId);
// ...
}
function recreate (id) {
// you can do the DOM manipulation here.
}
Edit: You can assign events to all your Scriptaculous draggables in this way:
Event.observe(window, 'load', function () {
Draggables.drags.each(function (item) {
Event.observe(item.element, 'mousedown', function () {
alert('mouseDown ' + this.id); // the this variable is the element
}); // which has been "mouse downed"
});
});
Check an example here.
CMS pretty much has the correct answer but you will need to make it a little more cross browser friendly.
document.body.onmousedown = function (e) {
// Get IE event object
e = e || window.event;
// Get target in W3C browsers & IE
var elementId = e.target ? e.target.id : e.srcElement.id;
// ...
}
Pls insert this code to your javascript.
document.getElementById("article").onmouseup(handMu);
If you want to replicate the div id, an easy way might be cloneNode like this:
<div id="node1">
<span>ChildNode</span>
<span>ChildNode</span>
</div>
<div id="container"></div>
<script type="text/javascript">
var node1 = document.getElementById('node1');
var node2 = node1.cloneNode(true);
node2.setAttribute('id', 'node2');
var container = document.getElementById('container');
container.appendChild(node2);
</script>