I have a div with onclick param:
<div onclick="some_function()"></div>
How can I access the event object inside the function? I need it to get event.target
function some_function()
{
event = event || window.event;
var target = event.target || event.srcElement;
//does not work in IE and Firefox, but works in chrome
}
This way:
<div onclick="some_function(event)"></div>
function some_function(evt)
{
// do something with evt (the event passed in the function call)
}
Note that the argument name MUST be event in the function call. In the event handler you can use the name you want.
A live example: http://jsfiddle.net/davidbuzatto/KHyAb/
If we work with event listeners, then you have in 'this' the html element and in 'event' the event object.
<a id="mya" href="#">Link</a>
var myA= document.querySelector("#mya");
myA.addEventListener("click", some_function);
function some_funtion() {
//Here the html element is: this
//Here the event object is: event
//event.target is not always equal to this
}
<div id="mydiv">click here <span>then here</span></div>
var myDiv = document.querySelector("#mydiv");
myDiv.addEventListener("click", other_function);
function other_function() {
alert(this === event.target);
}
Use the event to get to the target. Beware of target vs currentTarget issues:
https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget
<div onclick="some_function(event)"></div>
function some_function(event)
{
// event.target is the DOM element that triggered the event
}
Using event and this, both
document.querySelector("div").addEventListener("click", function(event) {
some_function(event, this);
}, false);
function some_function(currentEvent, currentObject) {
alert("Object is: " + currentObject.nodeName);
alert("Event is: " + currentEvent.type);
};
<div>Click Me</div>
<div onclick="some_function(this, event)"></div>
function some_function(elem, e)
{
//You have both: html element (elem), and object event (e)
//elem is not always equal to e.target
}
<div onclick="alert(this === event.target);">click here <span>then here</span></div>
Related
What is the JavaScript equivalent to this jQuery:
$(document).on('click', '.add-star', function (event) {
//event will return the .add-star
})
Markup looks like this
<div class="add-star">
<svg>
<path />
</svg>
</div>
When I do document.addEventListener('click', function(e) {... the e.target gets me the path not the parent add-star. From what I know with the jQuery way it bubbles up on the event looking for the class specified and returns that in the event. But there is no class specified with the JS event, so it returns just the immediate clicked element, the path from the svg.
How would I return add-star from the js event?
It's pretty easy. You just use .matches() on each element starting at e.target, traversing through each .parentNode until the bound element. When/if a match is found, you call the function.
So create a function that receives the callback and returns a new function handles this operation.
function delegate(selector, handler) {
return function(event) {
var el = event.target;
do {
if (el.matches(selector)) {
handler.call(el, event);
}
} while ((el = el.parentNode) && el !== this);
};
}
Then call that function to create the handler.
document.addEventListener('click', delegate('.add-star', function (event) {
//event will return the .add-star
}));
You have two main ways of handling events here, the event delegation method is similar to what your jQuery example is doing so I'll make that #1. This method uses e.target.matches to accomplish checking for an element that might not exist. The second method is for more traditional elements and uses document.querySelector
Method 1 delegated events
document.addEventListener('click', e => {
if (!e.target.matches('.add-star')) { return }
// do stuff
});
Method 2 non-dynamic selectors
let ele = document.querySelector('.add-star');
ele.addEventListener('click', e => { // do stuff });
I have a listener which runs when I click on document.
document.addEventListener('click', print);
function print(element)
{
doSomething();
}
It creates div id=panel, where I print some information.
When I run the print function I would like to detect whether I clicked outside of the div#panel (The panel exists when I click second time).
I wish not to use the mouseout event listener because I think it is redundant to use listener for mouse movements when the event click is already fired.
How to detect when I clicked out of div#panel?
You can check the target of jQuery's click event, which element it was:
$(document).click(function(e) {
var target = $(e.target);
if( !target.is("#panel") && target.closest("#panel").length === 0 ) {
// click was not on or inside #panel
}
});
Your event handler gets passed an event object, not an element. Since you are listening for the click event, the event will be of type MouseEvent and that event object will have a target property which you can use to check if the target element matches your desired element.
function handler(event) {
if (event.target == document.getElementById("panel")) {
// Do stuff
}
}
document.addEventListener('click', handler);
Edit: I intentionally gave the vanilla JS answer since your own code fragments don't use jQuery. But jQuery wouldn't change anything as its event handling API is almost just a thin wrapper over JS.
I am just using event from the click. Here it is
var elem=document.getElementById("elem");
var rects=elem.getBoundingClientRect();//get the bounds of the element
document.addEventListener('click', print);
function print(e)
{
//check if click position is inside or outside target element
if(e.pageX<= rects.left +rects.width && e.pageX>= rects.left && e.pageY<= rects.top +rects.height && e.pageY>= rects.top){
console.log("Inside element");
}
else{
console.log("Outside element");
}
}
JS Bin link : https://jsbin.com/pepilehigo/edit?html,js,console,output
A different approach, using only javascript is:
function print(evt) {
if (!(evt.target.tagName == 'DIV' && evt.target.classList.contains('myDiv'))) {
var div = document.createElement('div');
div.classList.add('myDiv');
div.textContent="new div";
document.body.appendChild(div);
}
}
window.onload = function() {
document.addEventListener('click', print);
}
.myDiv {
border:1px solid green;
}
I'm new to ES6, and can't quite get this to work:
$(this) returns undefined on click?
dom.videoLinks.click((e) => {
e.preventDefault();
console.log($(this));
var self = $(this),
url = self.attr(configuration.attribute);
eventHandlers.showVideo(url);
// Deactivate any active video thumbs
dom.videoLinks.filter('.video-selected').removeClass('video-selected');
// Activate selected video thumb
self.addClass('video-selected');
});
However if I change it so not be an arrow function like so, it works as expected?:
dom.videoLinks.click(function(e) {
e.preventDefault();
console.log(this);
console.log($(this));
var self = e.this,
url = self.attr(configuration.attribute);
eventHandlers.showVideo(url);
// Deactivate any active video thumbs
dom.videoLinks.filter('.video-selected').removeClass('video-selected');
// Activate selected video thumb
self.addClass('video-selected');
});
So how would I go about it if I use an arrow function in the callback?
With arrow function as a callback, instead of using this to get the element to which the handler is bound, you should use event.currentTarget.
Value of this inside an arrow function is determined by where the arrow function is defined, not where it is used.So from now on, keep in mind that
event.currentTarget always refers to the DOM element whose EventListeners are currently being processed.
.currentTarget vs .target
Use event.currentTarget instead of event.target because of event bubbling/capturing:
event.currentTarget- is the element that has the event listener attached to.
event.target- is the element that triggered the event.
From the documentation:
currentTarget of type EventTarget, readonly Used to indicate the
EventTarget whose EventListeners are currently being processed. This
is particularly useful during capturing and bubbling.
Check the basic example in the below snippet
var parent = document.getElementById('parent');
parent.addEventListener('click', function(e) {
document.getElementById('msg').innerHTML = "this: " + this.id +
"<br> currentTarget: " + e.currentTarget.id +
"<br>target: " + e.target.id;
});
$('#parent').on('click', function(e) {
$('#jQmsg').html("*jQuery<br>this: " + $(this).prop('id')
+ "<br>currenTarget: " + $(e.currentTarget).prop('id')
+ "<br>target: " + $(e.target).prop('id'));
});
$('#parent').on('click', e => $('#arrmsg').html('*Arrow function <br> currentTarget: ' + e.currentTarget.id));
#parent {background-color:red; width:250px; height:220px;}
#child {background-color:yellow;height:120px;width:120px;margin:0 auto;}
#grand-child {background-color:blue;height:50px;width:50px;margin:0 auto;}
#msg, #jQmsg, #arrmsg {font-size:16px;font-weight:600;background-color:#eee;font-family:sans-serif;color:navy;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="parent">Parent-(attached event handler)<br><br>
<div id="child"> Child<br><br>
<p id="grand-child">Grand Child</p>
</div>
</div>
<div id="msg"></div><br>
<div id="jQmsg"></div><br>
<div id="arrmsg"></div>
You wouldn't.
Changing the value of this is the primary point of using an arrow function.
If you don't want to do that then an arrow function is the wrong tool for the job.
You can use $(event.target) instead of $(this) even inside of an arrow function. Arrow functions are preserving this of the scope where they were defined. In your case it is undefined.
arrow functions and this selector?
Arrow functions retain this from enclosing context.
Eg.
obj.method = function(){
console.log(this);
$('a').click(e=>{
console.log(this);
})
};
obj.method(); // logs obj
$('a').click(); // logs obj
So how would I go about it if I use an arrow function in the callback?
You already can - to access event target you can use something like $(e.target), but beware of bubbling. So I recommend to use normal functions instead as callbacks.
I am twisting my mind and fingers finding why removeEventListenerwon't work. It should be a one time event, so I included the removeEventListener in the callback function, but the event fires every time.
var group = ...//some div's ID
var img_button = document.createElement("SPAN");
img_button.setAttribute("id","imgbutton_"+group);
if (figures.addEventListener){
figures.addEventListener(
'click', function(e){if (!e) e = window.event;e.stopPropagation();}, false);
img_button.addEventListener(
'mouseover', loadImg(group), false);
}else{...};
And the callback loadImg:
function loadImg(nodeId){//loading images when needed
return function(e){
if (!e) e = window.event;
[...]
//remove eventlistener when executed once
var sp = (e.target ? e.target : e.srcElement);
if (sp.removeEventListener){
sp.removeEventListener(
'mouseover', loadImg);
} else {...};
};
The anonymous function can stay but the loadImg I only need once. What did I forget?
loadImg is not the name of the listener function. You've attached an anonymous function which is returned from loadImg().
To solve this problem, you can give a name to the actual event handler function:
return function handler (e){
:
this.removeEventListener('mouseover', handler, false);
:
}
A working demo at jsFiddle.
this in event handler refers automatically to the element to which the event was attached.
Here's a fiddle illustrating the problem. I am adding a jQuery one binding on the click of one element to the 'html' element. I am not expecting the 'one' event handler to fire until the next click, but it fires on the click that adds the binding. This seems to not be a problem if it is a more specific element that the 'one' event handler is added to, but it happens when I use 'html' or 'body' as the element, which is what I want to do.
This doesn't make sense to me, I'd think the first click would add the one for the next click and it wouldn't fire on the click on the link.
By the way, my actual problem could probably be solved in a better way, but I came across this and was curious why it didn't work as I expected.
Code:
html:
<div id='hello'>hello</div>
<a class="title" href="#">this example</a> is a test
js:
$(function() {
$('a.title').click(function() {
var htmlClickBind = function (e) {
console.log('clicked on html, e.target = ' + e.target);
console.log(e.target == '');
if (!$(e.target).is('a') ) {
console.log('cleared click event');
}
else {
$('html').one('click', htmlClickBind);
}
};
$('html').one('click', htmlClickBind);
});
});
The click event on the a.target element bubbles up to the html element, where your (just-added) handler sees it.
To prevent this, use event.stopPropgation in your a.target click handler (or return false, which does stopPropagation and preventDefault).
Updated code (see the comments): Live copy
$(function() {
// Accept the event arg ----v
$('a.title').click(function(e) {
// Stop propagation
e.stopPropagation();
var htmlClickBind = function (e) {
console.log('clicked on html, e.target = ' + e.target);
console.log(e.target == '');
if (!$(e.target).is('a') ) {
console.log('cleared click event');
}
else {
$('html').one('click', htmlClickBind);
}
};
$('html').one('click', htmlClickBind);
});
});