I am trying run custom code whenever a click event is triggered. This is what I have so far:
const origHandler = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function (eventName, eventHandler, options) {
let handler = eventHandler;
const target = this;
origHandler.call(this, eventName, function (e) {
// Do something with e
doSomething(e);
// Run original function
handler.call(target, e);
}, options);
};
I am also using this multi-select dropdown plugin. With the code above, clicking on the dropdown element doesn't do anything until I click it a couple of times.
It works fine if I just do the following:
origHandler.call(this, eventName, handler, options);
However, the above doesn't allow me to run custom code whenever the handler is called. Is there anything I can do to create a wrapper that also works with these types of plugins?
This problem is not specific to this plugin, as I have seen a few other plugins in the application also breaking as a result of this code.
Incomplete Algorithm
The posted code calls (the original) addEventListener with an anonymous function argument. This means any removeEventListener in calling code which supplies handler as its function argument will fail - it never matches the anonymous function.
To successfully add a hook into addEventListener would require implementing a complementary hook into removeEventListener and additional logic to achieve correct removal of added listeners.
This doesn't mean the particular problems encountered are specifically caused by only patching addEventListener, but doing so is guaranteed to produce code failure.
In general patching prototype object properties of global functions is probably best avoided if at all possible.
Alternative using Capture
Adding a document click event listener that uses event capture, before including any library scripts, should allow inspection of every click event before being handled by anything else:
document.addEventListener("click", function(e){
// do something with event
console.log("click event type: %s on %s", e.type, e.target.tagName);
}, {capture:true});
body {background-color: white}
html {background-color: grey}
Click me!
Related
In Javascript, if an event is triggered and the corresponding callback is added to the message queue of the Javascript engine event loop. Is it possible to remove it from the queue through Javascript code?
Note that the events are called in high frequency, so it may be added to the event queue before any Javascript code is executed. I didn't see a description saying that removeEventListener actually goes through the message queue and remove corresponding events; want to double check if removeEventListener actually does that and such function is implemented the same way across all Javascript engines.
Standard Javascript does not offer any direct access to the event queue. You can listen for events (often with .addEventListener() or by registering callbacks and, when it is their turn, that event will fire and your callback will get called. Or, some listeners can be removed with .removeEventListener() or by canceling a specific operation (like clearTimeout()), but, there is no direct access to managing the event queue.
You would likely have to somehow have native code inside the VM in order to do that and how to do it would be non-standard and specific to a particular Javascript VM.
If you really just want to be able to easily prevent a callback from getting called more than once, then you can create a little stub that will do that for you.
function callOnce(fn) {
var called = false;
return function() {
if (!called) {
called = true;
return fn.apply(this, arguments);
}
}
}
// create a callOnce function stub for myFunction
var cb = callOnce(myFunction);
obj1.addEventListener("click", cb);
obj2.addEventListener("click", cb);
obj3.addEventListener("click", cb);
myFunction will only ever get called once whenever the first event calls it. After that, it will be blocked by the callOnce stub that was created when cb was defined.
Yes. its possible to unbind an event from object.
if you have used addEventListener to attach event then use removeEventListener to remove it.
if you have used jQuery .bind() then use .unbind() to remove it.
if you have used jQuery .on() then use .off() to remove it.
if you use attachEvent, you can use detachEvent().
If you use onclick or other similar functions then you can remove them by simply setting it to null.
ex. obj.onclick = null.
Well, when I learned JavaScript, all the books and Internet articles I read showed code passing a parameter e to functions that handle JavaScript events, such as the code block below:
function myEvent(e) {
var evtType = e.type
alert(evtType)
// displays click, or whatever the event type was
}
I've always accepted that as being the way it is, but now I have some questions (this is very confusing to me):
Where does this e come from? When I look at the entire JavaScript file, e does not seem to exist at all.
Why pass this parameter e to functions? Will functions stop working if I do not pass e to them?
Consider the code block below. There is an event variable (e) passed to an anonymous inner function. Let's say I want to use an event object outside of the anonymous function (maybe in a line above/below the element.onkeypress line). How can I do this?
element.onkeypress = function(e) {
if(e.keyCode) {
element.keyCode = e.keyCode;
} else {
element.keyCode = e.charCode;
}
};
The e is short for event
The simplest way to create an event is to click somewhere on the page.
When you click, a click event is triggered. This event is actually an object containing information about the action that just happened. In this example's case, the event would have info such as the coordinates of the click (event.screenX for example), the element on which you clicked (event.target), and much more.
Now, events happen all the time, however you are not interested in all the events that happen. When you are interested in some event however, it's when you add an event listener to the element you know will create events[1]. For example you are interested in knowing when the user clicks on a 'Subscribe' button and you want to do something when this event happens.
In order to do something about this event you bind an event handler to the button you are interested in. The way to bind the handler to the element is by doing element.addEventListener(eventName, handler).
eventName is a string and it's the name of the event you are interested in, in this case that would be 'click' (for the "click" event).
The handler is simply a function which does something (it's executed) when the event happens. The handler function, by default, when executed is passed the event object (that was created when the event/action you are interested in happened) as an argument.
Defining the event as a parameter of your handler function is optional but, sometimes (most times), it is useful for the handler function to know about the event that happened. When you do define it this is the e you see in the functions like the ones you mentioned. Remember, the event is just a regular javascript object, with lots of properties on it.
Hope that helped.
For more info read Creating and Triggering Events
As for your 3rd question, now you should know you cannot do that, because e only exists when an event happens. You could have the handler function, which has access to the e object when it gets executed, to store it in some global variable and work on that.
[1] That is not exactly correct, but it's simpler to understand. The more correct thing to say there is "add an event listener to the element you know will have events flow through it". See this for more information
The parameter e that you are asking about is an Event object, and it
represents the event being fired which caused your function to be executed. It doesnt really have to be e, you can name it anything you want just like all other function parameters.
Where does this e come from? When I look at the entire javascript file, e
does not seem to exist at all.
You won't be able to find this e variable in your javascript file because
it's really not there at all, but comes from the javascript engine executing
your callback function.
When you give a callback function for some event
(e.g. element.onkeypress = function(e) { ... }), you are giving the
javascript engine a function to execute/call when that event fires, and when
it executes/calls your callback function it passes along an Event object
representing the event that just happened. Javascript could be doing something
like this to call your callback function:
var e = new Event();
callbackFunction(e);
and that's where the Event object e comes from.
Why pass this parameter e to functions? Will the function stop working if
I do not pass e to it?
The function will not stop working if you don't have the e parameter in it.
But if you need to access some details about the event that caused your
function to be executed, you are going to need the e parameter to get them.
Consider the code block below, there is an event variable(e) passed to an
anonymous inner function. Lets say I want to use event object outside of the
anonymous function(maybe in a line above/below the element.onkeypress line),
how can I do this?
I dont think you can do this, even if you store it in a variable outside the
scope of your callback function. This is because your function is not executed
right away when you declare it, but instead only when the event is fired
(e.g. a key is pressed, firing the 'keypress' event).
var event;
element.onkeypress = function(e) {
event = e;
...
};
console.log(event); // => undefined
The only way this could work is when the code that uses the event variable
also gets executed later, specifically after the anonymous function given to
onkeypress gets executed. So the code below could work:
var event;
element.onkeypress = function(e) {
event = e;
...
};
setTimeout(function() {
console.log(event); // => the event object, if the `keypress` event
// fired before `setTimeout` calls this function
}, 100000); // <= set to very large value so that it gets run way way later
I will try my best to explain in the most abstract way possible. The real implementation is probably a lot more complex. Therefore, the names that I am about to use are hypothetical but they do serve a good purpose for explaining things, I hope ;)
Every node in the browser is an implementation of EventEmitter class. This class maintains an object events that contains key:value pairs of eventType (the key) : an Array containing listener functions (the value).
The two functions defined in the EventEmitter class are addEventListener and fire.
class EventEmitter {
constructor(id) {
this.events = {};
this.id = id;
}
addEventListener(eventType, listener) {
if (!this.events[eventType]) {
this.events[eventType] = [];
}
this.events[eventType].push(listener);
}
fire(eventType, eventProperties) {
if (this.events[eventType]) {
this.events[eventType].forEach(listener => listener(eventProperties));
}
}
}
addEventListener is used by the programmer to register their desired listener functions to be fired upon the execution of their desired eventType.
Note that for each distinct eventType, there is a distinct array. This array can hold multiple listener functions for the same eventType.
fire is invoked by the browser in response to user interactions. The browser knows what kind of interaction has been performed and on what node it has been performed. It uses that knowledge to invoke fire on the appropriate node with the appropriate parameters which are eventType and eventProperties.
fire loops through the array associated with the specific eventType. Going through the array, it invokes every listener function inside the array while passing eventProperties to it.
This is how the listener functions, registered only with the particular eventType, are invoked once fire is called.
Following is a demonstration. There are 3 Actors in this demonstration. Programmer, Browser and the User.
let button = document.getElementById("myButton"); // Done by the Programmer
let button = new EventEmitter("myButton"); // Done by the Browser somewhere in the background.
button.addEventListener("click", () =>
console.log("This is one of the listeners for the click event. But it DOES NOT need the event details.")
); // Done By the Programmer
button.addEventListener("click", e => {
console.log(
"This is another listener for the click event! However this DOES need the event details."
);
console.log(e);
}); // Done By the Programmer
//User clicks the button
button.fire("click", {
type: "click",
clientX: 47,
clientY: 18,
bubbles: true,
manyOthers: "etc"
}); // Done By the Browser in the background
After the user clicks on button, Browser invokes fire on button passing "click" as an eventType and the object holding eventProperties. This causes all the registered listener functions under "click" eventType to be invoked.
As you can see, the Browser ALWAYS puts eventProperties on fire. As a programmer, you may or may not use those properties in your listener functions.
Some answers that I found helpful on stackoveflow:
Where is an event registered with addEventListener stored?
Where are Javascript event handlers stored?
When a listener is added using addEventListener, the first argument passed to the function is an Event object, so it will be assigned to the e parameter (or whatever name is given to the function's first parameter).
It's just how JS works, you get event object in every event callback. It contains a lot of info about the event.
Function will not stop working if you do not pass it, it is optional. Go on and console.log the event (e) and see the event object and its properties. It will be more clear when you see what it has.
You can use it outside of that anonymous function by storing it, example:
var myEvent;
element.onkeypress = function(e) {
myEvent = e;
if(e.keyCode) {
element.keyCode = e.keyCode;
} else {
element.keyCode = e.charCode;
}
};
console.log(myEvent);
but you should know that the event object is relative only to that specific event that happened, and considering that you should decide if you really need to do that.
So I'm trying to gain advance Javascript skills. So I'm doing a practical JS tutorial on Lynda.com. Chapter 3 is on EventHandlers and I'm a little confused (Note: I've deleted the code that makes the script work in all browsers). I've rewatched the videos and that hasn't been helpful at all.
What is the e referring to? I don't have a variable at all named e or anything else that I can see.
What is false referring to? Is it the same as return false since I'm dealing with a link?
function clickLink(e) {
alert("You Clicked the Link");
}
function linkClicked(e) {
addEventHandler(document.getElementById("clickLink"), "click", clickLink, false);
}
addEventHandler(window, "load", linkClicked, false);
The e just refers to the event that has taken place, you can change it to anything you want. It just passes the event around to the various functions etc. that need to use it.
The false simply means that the event is not 'consumed', i.e. it can be used by other handlers if you have multiple handlers for the same event. So, yes, it is effectively the same as return false. (see my link below about bubbling)
See here for more on consuming events and bubbling.
First of all e is just an argument that you will receive in the function. You could also write something like this:
function evtHandler(){
console.log(arguments[0]);
}
Where arguments[0] is your given e. The handler function is called when the event is fired. Usually in the e argument you have an object with some info about how fire the event.
When you add an event handler, the last argument on that function is a boolean one, which indicates if the handle should or shouldn't bubble in the event handler's chain. It is not as you would return false, but if the event would be handled by other handlers also. If you want to return false or ignore the previous default handling you could call the preventDefault function inside the evtHandler.
P.S. Take care with event handlers because there are some problems with cross-browser compatibility;
if you are talking about e in clickLink(e), then i can say you can declare whatever parameter you want in a javascript function prototype,but when calling it you can provide parameters optionaly.and here in clickLink(e) you can pass a parameter for e or you can simply ignore it.and about the false in addEventHandler check this documentation also check this SO question .
for example if function FO is defined so:
function FO(e){
//function body here
}
then you can call it like this :
FO();
OR
FO("BAR");
What is the difference between event handlers and event listeners in JavaScript? They both execute a function when the event appears.
I don't really get when to use event handlers and when to use event listeners.
A handler and a listener are one in the same - just synonyms for the function that will handle an event. "Handler" is probably the more accepted term, and is certainly more semantically correct to me. The term "listener" is derived from the code used to add an event to an element:
element.addEventListener('click', function() { /* do stuff here*/ }, false);
You could, however, get really nitpicky and break the two down into separate meanings. If you're so inclined, "handler" could be the term for the function that is going to handle an event when you add a "listener", thus one can have several "listeners" that utilize a single "handler". Consider:
// handler is synonymous with function
function someFunction(e) {
if (typeof e == 'undefined')
alert('called as a function');
else
alert('called as a handler');
}
// use someFunction as a handler for a
// click event on element1 -- add a "listener"
element.addEventListener('click', someFunction, false);
// use an anonymous function as a handler for a
// click event on element1 -- add another "listener"
element.addEventListener('click', function () { alert('anonymoose'); }, false);
// use someFunction as a handler for a
// click event on element2 -- add a "listener"
element2.addEventListener('click', someFunction, false);
// call someFunction right now
someFunction();
So in the above code, I have 2 "handlers" (someFunction and an anonymous function) and 3 "listeners".
Again, this is all semantics - for all practical purposes the terms listener and handler are used interchangeably. If a distinction need be made then a listener is a subscription to an event that will trigger a call to a handler (which is a function).
Clear as mud?
There's no difference; it's just different terminology for the same thing.
There are different ways of associating functions with DOM elements for the purpose of event handling, that's all. The differences emerged back when standards were in flux (or just because implementors were ornery or difficult) but ultimately the mechanisms are essentially the same.
If you're confused about what sort of event handler registration to use, you can:
Read more about the topic and choose an approach to use, perhaps on a browser-by-browser basis;
Choose one of the popular JavaScript frameworks and use its mechanism for attaching handlers
This site, (which funnily enough has a cyclical reference to here by one of the comments) states otherwise, to what people have answered here (stating they are same); pasting one of the answers:
One difference is that if you add two event handlers for the same button click, the second event handler will overwrite the first and only that event will trigger. For example:
document.querySelector('.btn').onclick = function() {
console.log('Hello ');
};
document.querySelector('.btn').onclick = function() {
console.log('World!');
};
// This logs "World!" out to the console.
But if you use addEventListener instead, then both of the triggers will run.
document.querySelector('.btn').addEventListener('click', function() {
console.log('Hello ');
});
document.querySelector('.btn').addEventListener('click', function() {
console.log('World!');
});
// This logs "Hello" and "World!" out to the console.
I find this explanation particularly hands-on:
Event handlers are comprised of an event listener and a callback function.
An event listener specifies the type of event that will be detected.
The callback function executes when the event happens.
Everything together is the event handler.
both of them used for associating a function when an event occurs, if using the event listener's you can listen more than once in A specified event (duplicate) for example listen to tow 'click' event into independent event listener's, but when using the handler it's impossible because handler is a property of your dom object and if Assign more than once a function in same event handler, for example, when set to the a element tow handler for onClick event, the last event handler assignment is work.
myElement= document.querySelector('#btn');
myElement.onClick = function(){
alert('first event handler');
}
myElement.onClick = function(){
alert('second event handler');
}
// result : occur last handler >> alert('second event handler');
but if using the event listeners you can listen to how many times listen to the same
event.
myElement.addEventListener('click',()=>{
alert('first listener')
})
myElement.addEventListener('click',()=>{
alert('second listener')
})
/* result : occur both listeners - alert('firstlistener') >> and next >> alert('second
listener'); */
there's no big difference.
we can say they are almost the same things except for three subtle things that are:
you can use an event handler once. if you use a handler to an element twice or more, then the last handler will overwrite all those previous handlers.
on the other hand, if you use event listeners more then once, there won't be such a thing like this.
you can use many event listeners, but not just one.
For some events, handlers only work with addEventListener. like the DOMContentLoaded event, which triggers when the document is loaded and DOM is built.
whit using event listeners, you can pass an object or class by using handleEvent on them instead of a function to the handler.
except for these subtle things, I don't think it exists any difference.
For more information see
https://javascript.info/introduction-browser-events#object-handlers-handleevent
I have a Javascript module the following Javascript:
EntryController = function$entry(args) {
MainView();
$('#target').click(function() {
alert('Handler called!');
});
}
MainView() has a callback that creates the #target button. Because of the callback the code will pick up and run through the rest of the code $('#target') ... before #target is created. If this is the case the event is never hooked up to the #target. If I put a breakpoint at $('#target') that'll give the callback enough time to return and build the #target, when I press play everything works as expected.
What's the best way to deal with this? I would like all events to take place in the controller so it can choose which view to send it to.
I was thinking about placing the entire $('#target').click ... inside MainView() and instead of alert('Handler called!'); I'd put a references to EntryController.TargetEventRaise(), but that started to look a bit like steady code. What's the best way to approach this?
You're looking for jQuery's live event handlers, which will handle an event on every element that matches the selector, no matter when the element was created.
For example:
$('#target').live('click', function() {
alert('Handler called!');
});
Alternatively, you could make the MainView function itself take a callback, and add the handler in the callback. You could then call the callback in MainView inside of its callback.