Using this inside an event handler - javascript

I was trying to find the meaning of this keyword inside event handler function in the DOM level 3 event spec.
As per my experiment this refers to the event.currentTarget object.
Is this behavior mentioned somewhere in the standard?
As per "JavaScript The Definitive Guide" book this refers to the event target which seems to wrong. event.currentTarget seems more logical as event handlers are invoked as the method of the HTML element object.
Can someone please clarify?
In case of bubbling I see "this" changes and means the
event.currentTarget.

Indeed, the Definitive Guide is wrong in that case.
I found a reference in the HTML5 event handler processing algorithm:
Invoke callback with one argument, the value of which is the Event object E, with the callback this value set to E's currentTarget.
The DOM level 3 event specification didn't say much about it in previous versions - it was meant to be language agnostic. The Appendix F: ECMAScript Language Binding just stated
EventListener function:
This function has no return value. The parameter shall be an object that implements the Event interface.
However, current versions omitted these bindings. And in its Glossary appendix event listeners are described:
event handler, event listener: An object that implements the EventListener interface and provides an EventListener.handleEvent() callback method. Event handlers are language-specific. Event handlers are invoked in the context of a particular object (the current event target) and are provided with the event object itself.
Also, the upcoming DOM Level 4 draft, whose goals contain aligning the DOM with the needs of EcmaScript, does explicitly state in the Dispatching Events section:
If listener's callback is a Function object, its callback this value is the event's currentTarget attribute value.

In an event handler for an element, with default capturing (false), this will refer to the element which detected the event. Either one may be used.
For example:
element.addEventListener('keydown', function (event) {
// `this` will point to `element`
}, false);
When capturing an event (true), say at the window level, event.target, will refer to the element which originated the event, while this will refer to the capturing element. For example:
window.addEventListener("error", function (event) {
event.target.src = 'some_path';
// `this` will point to window
// `event.target` will point to the element that had an error
}, true);
I hope this exemplifies the difference between each.

Related

Why is the value of `this` in a dom event listener callback not the window?

Let's look at the following code:
const div = document.getElementById('foo');
div.addEventListener('click', function() {
console.log(this);
});
<div id="foo">click me</div>
This button will always log the dom element I'm clicking. I've always known this to be true, and I know that I can use an arrow function here to make the value of this the window. We are assuming non arrow function syntax for this question.
To my knowledge, the value of this gets its value based on how the enclosing function is invoked. The callback of this event listener certainly doesn't get called on the dom element.
In my mind, when the div gets clicked, it adds the anonymous function to the message queue. When the queue is empty it invokes the anonymous function in a global execution context (perhaps this is where I'm wrong).
If it is in the global execution context where this anonymous function gets invoked, shouldn't the value of this be the window?
Which leads back to the title question, why is the value of this in a dom event listener callback not the window? (Assuming the callback is not an arrow function)
It's because it's a method attached to the div object - think of it like this:
const div = {
addEventListener: function(event, callback) {...}
};
In this example, this would refer to div as you would expect.
This is what's actually happening in your code, only it's being defined differently.
The value of this within the handler
It is often desirable to reference the element on which the event handler was fired, such as when using a generic handler for a set of similar elements.
If attaching a handler function to an element using addEventListener(), the value of this inside the handler is a reference to the element. It is the same as the value of the currentTarget property of the event argument that is passed to the handler.

What parameters can you pass to html attribute onchange, onclick, etc.?

When I started learning javascript I thought that the browser would simply run the javascript in onclick attribute of elements as if it was inside a script tag. However I realize that is not the case because you can use certain parameters inside these attributes. For example onclick="foo(this, event)" passes the event triggered and the element that the event was triggered on to function foo.
I wonder what other parameters can be used inside these tags? The documentation on w3schools does not mention anything about this. I would also like to know how these attributes are implemented; how is the function called and in what scope (I know that foo will be called like element.foo() but this is not true for other javascript expressions). Is there a comprehensive documentation anywhere? my best guess at the moment is that the implementation looks like this:
element.onclickfunction = function(){
var event = new Event(...)
eval(element.onclick)
}
Edit:
none of the responses really answered my question. I was interested to know what other special parameters can be passed to the function specified in an event handler and how the parameter this is interpreted to be the Element. I am picking the best answer because he provided a link to mdn where EventHandler interface is described.
In JavaScript, you can register an event listener on any DOM element, the document itself, the context window, or any other objects that support events. There are a whole bunch of events that are defined in a whole bunch of web standards. A good resource that lists these out is the Mozilla Developer Network.
The EventListener that gets registered to the event only takes one parameter: the event. You can see that it only has one method, handleEvent, which takes only one parameter.
To pass other stuff into the event handler, you can take advantage of closures or bind(). I'm going to borrow from this answer to demonstrate how bind() works:
elem.addEventListener(function(a1, a2, e) {
// inside the event handler, you have access to both your arguments
// and the event object that the event handler passes
}.bind(elem, arg1, arg2));
Binding elem, arg1, and arg2 to the function means that the this of the function becomes elem, and the first two arguments of the function become arg1 and arg2. The e argument is still the event that triggered the function, just like always. Binding stuff like this is super useful when you want to pass stuff from outside the event handler to inside the handler. You can read more about bind() here.
With regards to your specific question about onclick(), the principle is basically the same except your registering a specific click event handler to an element. It too only takes one argument, and that is the MouseEvent object. But like with any function, you can still bind other arguments to it. See here for more info.

this and DOM on-event handlers

The following statement on MDN seems not true:
When the event handler is invoked, the this keyword inside the handler
is set to the DOM element on which the handler is registered.
(source)
This statement is about an on<...> event handler not addEventListener.
<p><a id="link" href="#" onclick="EventHandler();">click me</a></p>
<script>
function EventHandler() {
console.log(this);
//the this keyword inside the handler is NOT set to the DOM element
//it sets to the window object
}
</script>
which contradicts with the statement on MDN.
Of course, you can pass the this as an parameter to EventHandler or simply use addEventListener.But that is off topic.
The topic of the question isthis and an on<...> event handler.
My question is: Is that my understandig is not correct or is the statement on MDN is not correct?
This statement is true whenever the event handler is inlined, as it's stated in the link right after the sentence you quoted.
But, in your case, MDN specify :
When a function is used as an event handler, its this is set to the
element the event fired from (some browsers do not follow this
convention for listeners added dynamically with methods other than
addEventListener).
I've tested in latest Chrome & FF, these browsers don't follow this convention.
According to the specs, this inside event listeners/handlers will always be the current target of the event:
Event listeners:
Call listener's callback's handleEvent, with the event passed
to this algorithm as the first argument and event's currentTarget
attribute value as callback this value.
Event handlers
If E is an ErrorEvent object and the event handler IDL attribute's type is OnErrorEventHandler
Invoke callback with five arguments, [...] and with the callback this value set to E's currentTarget.
Otherwise
Invoke callback with one argument, the value of which is the Event object E, with the callback this value set to
E's currentTarget.

What is the meaning of 'function(event)' in js

I don't know the meaning of the sentence 'function(event)'
Event.add(apple,'click',function(event) {
Event.stopPropagation(event);
});
Isn't the argument 'event' is the unique keyword of javascript?
Is keyword can be an argument of some function?
I understand the meaning of below code :
function(test) {
alert(test);
}
But I don't understand this one :
function(event)...
Can any one give an explanation about that to me?
The event object is always passed to the handler and contains a lot of useful information what has happened.
Different types of events provide different properties. For example, the onclick event object contains:
event.target - the reference to clicked element. IE uses event.srcElement instead.
event.clientX / event.clientY - coordinates of the pointer at the moment of click.
Information about which button was clicked and other properties.
Please visit this link.
It answers all your questions very simply
Source http://javascript.info/tutorial/obtaining-event-object
Example:
Like if in HTML you have assigned an event like this
<button onclick="alert(event)">See the event</button>
then
function alert(event) {
// event.type contains whether this event was invoked in the result of a click etc
// event.target would contain the reference to the element which invoked this method/event
}
It is an anonymous function, that is a function without name, that sends the event object. That object contains information about the event itself. It is always passed as first object/variable.
It is defining an anonymous function object. This code:
function foo(bar) { ... }
Is functionally similar to:
var foo = function (bar) { ... };
(Except that in the first case the name foo and the creation and assignment of the function object are hoisted to the top of the scope, while in the second case only the name foo is hoisted; foo won't hold the function until the assignment executes.)
Effectively, the code you posted is calling Event.add() and passing a function to it as the third argument, but rather than declaring the function ahead of time it is creating the function object inline.
Another way to write the code block in your question is:
function handler(event) {
Event.stopPropagation(event);
}
Event.add(apple, 'click', handler);
Except that the code in your question does not introduce the handler name.
Note that there is no such method Event.stopPropagation(). However, the event object will have a stopPropagation(), so the capital E was probably a typo. It's likely that the intent was to use function (event) { event.stopPropagation(); }.
event is just a variable that's passed to event listener functions such as Event.add, element.on. It's not reserved (although Event is, which is why you can use Event.add), and you can name it whatever you like.
The event argument is used to pass information about the event that has happened (the click on apple in this case), which can be used to retrieve data about the event or manipulate it.
function(){...} is an anonymous function, which means that you don't need to name it, you can just declare it inline, and the function will be passed as an argument, as if you said
function foo (event) {
...
}
Event.add(apple, "click", foo);
but you don't need to declare it before hand. It does come at the disadvantage of not being duplicable, for instance when clearing an event handler.
Look at the event variable and you will all understand :)
function (event) {
console.log({ event });
}

Where does the 'event' param come from in javascript event handlers?

Often I see javascript code where event handlers (like onmousemove) are assigned dynamically.
Example:
document.getElementById('foo').onmousemove = function(e)
{ /* do some stuff with event e */ }
Apparently this 'e' parameter is some kind of event object. Where does that come from, as in: who or what defines what this 'e' parameter is when the function is called, and can I also do this in static html?
I mean like this:
<div id='foo' onmousemove='Bla(e)'> ... </div>
What should I fill in for 'e' to get that same event thing? And can I also combine that with more parameters, like
<div id='foo' onmousemove='Bla(this,e,4)'> ... </div>
where e is, again, supposed to be the event object?
Event handlers are defined as callback methods. A callback is (hence the expression) called from another process at a later time. This is done by the environment (the browser in this case) at the time an event fires.
it calls your callback function and passes in the event object.
The event object is stored in window.event inside of any event handler, so you do not need to worry about your handler conforming to accepting it as a parameter.
In your second and third examples, the e parameter will be passed as undefined because no variable e exists in that scope (unless you have a global e).
This is what's known as a callback method. The event is initially created by the operating system, sent to the web browser, which then passes it off to you in javascript Event object.
I'm not sure, but I think the event is an object instance of ActionEvent. I don't think ActionEvent can be manually instantiated, so you can't do it in static HTML. Even if it would be possible, it certainly wouldn't be best practice.

Categories