Javascript: Stop onClick default - javascript

I get the feeling I am missing something obvious but just can see it.
A trigger on the click event is set:
anchor.addEventListener("click", myClickEvent );
function myClickEvent() {
this.preventDefault(); // fails
return false;
}
However the default onClick method still happens.
Can I cancel default propogation at the same time as I addEventListener or is there some other way of doing this. I cannot use .preventDefault() from within myClickEvent because the event is not available at that point.
Edit following comments for clarity:
The default onClick of the tag happens even though myClickEvent returns false.

element.addEventListener("click", myClickEvent );
function myClickEvent(event) {
event.preventDefault();
return false;
}

Returning false from a handler that was registered with addEventListener does nothing. See https://stackoverflow.com/a/1357151/227299 and https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault
The recommended way is to call event.preventDefault()
function myClickEvent(e) {
e.preventDefault()
}
Handlers from HTML attributes still work, but you should not use it since it's not as clear what return false means when compared to event.preventDefault() (not allow the link to be followed) and event.stopPropagation() (don't let the event bubble up)

There is no such function in the global scope called preventDefault -- you need to use the event that has been passed into your callback.
Also please make sure that you are attaching the event to something that can be clicked on (a form, anchor, button etc) that can potentially have an event prevented.
If you attach the event to a child/parent element nothing will work as you expected.

Nearly there thanks to Teemu's code but not quite.
There is a difference depending on how the function is called. Seemingly there is both a hidden parameter sent defining the value of 'this' and when called without parameters an automatic event object sent as the first visible parameter:
Call it without parameters:
anchor.addEventListener("click", myClickEvent );
function myClickEvent(param1, param2) {
// this = events parent element (<a>)
// this.href = <a href=...>
// param1 = event object
// param2 = undefined
oEvent = param1;
oEvent.preventDefault();
}
but then call it with parameters:
anchor.addEventListener("click", function (oEvent) { myClickEvent(oEvent, myParameter); });
function myClickEvent(param1, param2) {
// this = [object Window]
// this.href = undefined
// param1 = event object
// param2 = myParameter
oEvent = param1;
oEvent.preventDefault();
}
Notice how when parameters are sent manually the value of 'this' changes from the events parent element to '[object Window]', causing this.href to go wrong.
However the preventDefault now appears to be working reliably.

Related

Cannot pass a parameter to the function through addEventListener

I have the following function:
export function myoutsideClickHandler(menuRef) {
console.log("%%%%%%%%%%%%%%%%%%%%%%%%%%");
console.log(menuRef);
document.addEventListener('click', (menuRef)=>test1(menuRef), false);
}
I can see that menuRef is printed and has value. So far so good.
Now in test1() function, I have:
export function test1(e, menuRef){
console.log(menuRef);
}
In the console, I see undefined which means that menuRef has not been sent via addEventListener
Am I wrong with the way I am passing menuRef parameter?
The way you are binding the event is wrong. menuRef in your click is going to be the event. You are not passing a second argument. Your click handler should be:
document.addEventListener('click', evt => test1(evt, menuRef), false);
You can use an anonymous function to trigger a callback function that requires multiple parameters. So in your case, changing your myoutsideClickHandler() function to the following should work:
export function myoutsideClickHandler(menuRef) {
console.log("%%%%%%%%%%%%%%%%%%%%%%%%%%");
console.log(menuRef);
document.addEventListener('click', function(e) {
test1(e, menuRef);
}, false);
}
However, I should note that you're not using event handlers correctly, they should be called and set up outside of click handler functions, so you may want to read up on that to avoid future issues.

Function Call as parameter of another function on Javascript

First of all, i need this to be capabe to run on I.E. 8 at least (work requirements) and i can't use jQuery or another library to reach this.
The "issue" is that there's a function onKeyDown with a preventDefault and a function triggered onChange, which never (or randomly) executes due to prevendefault (long to explain more). I't could be solved as i'm reading onChange value and i'm setting it as onPlay, then i delete onchange attribute and the behaviour is to check if changes exists when onBlur and i'm triggering onplay event from this control function if there are changes.
Well, onPlay event (and other multimedia events) are only supported on IE 9 and up, so i need to find a way to pass through this. i can't use other events as they could be used on somewhere and could cause issues.
My idea was to send onChange value as function parameter to control function and execute it instead on triggering onplay event, but is causing me headache, it simply does nothing when i'm trying to do it.
//this is a resume of the function:
function foo(obj){
var funcioChange = toString(obj.getAttribute('onChange'));
obj.setAttribute('onBlur', 'checkChanges("'+obj.getAttribute("id")+', '+ funcioChange+'")');
obj.removeAttribute('onChange', 0);
}
When onBlur:
function checkChanges(idinput, functOnChange){
if (foo){
functOnChange;
//another things
}
}
If the function doesn't have parameter/s or you need to put it/them later in another function, you can do
foo = yourFunction;
function2 (foo){
foo(param1, param2);
}
if you have to send the params with the function call:
foo = "yourFunction(param1, param2)";
function2 (foo){
foo;
}

is this a valid way to define an explicit function inside addEventListener?

Just wondering, is this a valid way to define an explicit function inside JavaScript's addEventListener function so that it could be removed at any time using removeEventListener?
var somefunction;
window.addEventListener('load', somefunction = function(){
//do something
}, false);
window.removeEventListener('load', somefunction, false);
In other words, is it ok to define a variable somefunction and then assign an anonymous function to it inside addEventListener, instead of defining somefunction outright from the get go? It seems to work in FF and Chrome, but just wanna make sure this is officially valid JavaScript syntax.
Yes, it will work. An assignment is an expression -- it assigns to the variable and also returns the value that it assigned.
Personally I think this is a confusing way to write it. If you're refer to the function by name, put the definition where you define the name, not where you use it. In particular, if you try to do this twice, you'll have a problem because each event listener will have a different function, but it has the same name.
window.addEventListener('event1', somefunction = function() {
//do something
});
window.addEventListener('event2', somefunction = function() {
//do something
});
Now you can only remove event2, because somefunction no longer refers to the function that was added to event1.
Calling removeEventListener() with arguments that do not identify any
currently registered EventListener on the EventTarget has no effect.
So as long as removeEventListener has say a 'click' event as an argument, any one eventListener registered to the 'click' event will be removed. This is evident in OP's case, therefore it is feasible according to the criteria previously mentioned.
The following Snippet demonstrates a registered eventListener added to #target1 to listen for the 'click' event. It will be functional until removeEventListener() is called to remove the eventListener within 4 seconds. Notice that this particular removeEventListener's arguments are:
the event object............: click
a named function..........: eventLog()
and it's capture boolean: false
The identifying argument is 'click' and the target.event is #target that allows removeEventListener() to identify it's target.
SNIPPET
var eventLog;
var tgt1 = document.getElementById('target1');
var term = document.getElementById('btn');
tgt1.addEventListener('click', eventLog = function(e) {
console.log('target1 has been clicked');
}, false);
setTimeout(function() {
tgt1.removeEventListener('click', eventLog, false);
eventLog('Target1 eventListener is removed');
}, 4000);
function eventLog(str) {
console.log(str);
}
#target1 {
border: 2px solid red;
}
<p>Start clicking TARGET1 several times and you'll notice that each `click` event is firing as displayed in the console. Within 4 seconds, TARGET1's eventListener should be removed.</p>
<div id='target1'>TARGET1</div>

What exactly is the parameter e (event) and why pass it to JavaScript functions?

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.

How can I add an event for a one time click to a function?

I would like to add a click event listener to a function but would only like it to happen once. How could i do this?
I would like to stay clear of JQuery as well if it is possible please.
EDITED
As the answers that I am getting for this are fully satisfying my need i thought i may make it a bit more clear with context.
I am writing a function to draw a rectangle, first with one click on a button to initiate the rectangle function. Then there are two click event listeners in the drawRectangle function. These are the events i would like to happen only once in the function. Allowing the user to then create another rectangle if they click on the rectangle initiation button again.
Use modern JavaScript!
EventTarget.addEventListener("click", function() {
// Do something cool
}, {once : true});
A Boolean indicating that the listener should be invoked at most once after being added. If true, the listener would be automatically removed when invoked.
- MDN web docs
All modern browsers support this feature
Other reference
You have to use removeEventListener once the event is fired once. However, removeEventListener takes a function as argument, which means you need to declare a named function, add it with addEventListener, and have it removing itself. Example:
function foo() {
// do things, then
removeEventListener('click', foo);
}
addEventListener('click', foo);
function one(el, type, fn) {
function handler(event) {
el.removeEventListener(type, handler);
fn(event);
}
el.addEventListener(type, handler);
}
// use it like
one(window, 'resize', function () {
alert("This triggers just once");
});
Example: http://jsfiddle.net/6njpem7x/
The other answers are correct in that this can be achieved with a named function, but you don't need to declare the function separately. You can use a named function expression:
element.addEventListener("click", function handler(event) {
this.removeEventListener("click", handler);
// ...
});
An alternative, though less optimal, approach is to keep around a variable that keeps track whether the handler was executed:
var wasExecuted = false;
element.addEventListener("click", function(event) {
if (wasExecuted) {
return;
}
wasExecuted = true;
// ...
});
The variable needs to be declared outside the handler but within scope, so that its value persists across event triggers.
Combination of addEventListener and removeEventListener:
element.addEventListener("click", clickFunction);
function clickFunction(e) {
console.log("clicked");
element.removeEventListener("click", clickFunction);
}
jsFiddle
something like this
var el = document.getElementById('something');
el.addEventListener('click', doSomething);
function doSomething() {
el.removeEventListener('click', doSomething);
//code
}
Inside event handler you can use universal: e.target.removeEventListener(e.type, arguments.callee)
Or you can make special function for creating "one time" event listeners:
function oneTimeListener(node, type, callback) {
// create event
node.addEventListener(type, function(e) {
// remove event listener
e.target.removeEventListener(e.type, arguments.callee);
// call handler with original context
// as it happens with native addEventListener
return callback.call(this, e);
});
}
oneTimeListener(document.getElementById("myElement"), "click", myHandler);
You can set a cookie after first click:
document.cookie="click=1; expires=.......";
and add condition to listener - if cookie is set, you omit that.
Another simple solution which I'm using is to add a dummy class to the element to which we are listening so that it will not fire again.
const myButton = document.querySelector('#my-button:not(.init)');
myButton.addEventListener('click', (e) => {
e.preventDefault();
myButton.classList.add('init');
});

Categories