<script>
var ohnoesEl = document.getElementById("ohnoes");
var onOhNoesClick = function(e) {
e.preventDefault();
var audioEl = document.createElement("audio");
audioEl.src = "https://www.kasandbox.org/programming-sounds/rpg/giant-no.mp3";
audioEl.autoplay = "true";
document.body.appendChild(audioEl);
};
ohnoesEl.addEventListener("click", onOhNoesClick);
</script>
In this code, I didn't understand one thing. I checked internet and StackOverflow but couldn't find anything.
I have a problem to understand event property.
Why do we put e as an argument before we use properties such as preventDefault?
How will I realize whether I should use it or not?
I have a problem to understand event property.
Well, it's not a property. All event handling functions are automatically passed a reference to the event object that represents the event currently being handled. This object can tell you quite a bit about the circumstances at the time of the event (i.e. which mouse button was clicked, what key was pressed, where on the screen the mouse was when the click happened, what object triggered the event, etc.).
Why do we put e as an argument before we use properties such as
preventDefault?
The syntax of e.preventDefault() is simply common Object-Oriented Programming syntax of: Object.method(). We are accessing the Event object that was passed into the function with the e identifier and then invoking the preventDefault method stored within that object.
It's how you get at some object-specific behavior. .preventDefault() is not a global function, you can't just call it on its own. It's only something that an event object can do, so you have to reference the object before calling the method.
As with all function arguments, you may call the argument any valid name you like, but since the object will be an event object, e, evt, and event are quite common.
How will I realize whether I should use it or not?
In your code: e.preventDefault(), indicates that the event that was triggered should not perform its built-in action, effectively cancelling the event.
You would use this technique in situations where the user has initiated some event, but your code determines that the process should not continue. The best example is with a form's submit event. If the user hasn't filled out all the required fields and then hits the submit button, we don't want the form to be submitted, so we check to see if the required fields were filled in and, if not, we cancel the submit event.
Here's an example:
// Get a reference to the link:
var link = document.getElementById("nasaLink");
// Set up a click event callback function that will automatically
// be passed a reference to the click event when it occurs. In this
// example, the event will be received as "evt".
link.addEventListener("click", function(evt){
console.clear(); // Cancel previous log entries
// Get the type of event that was received and the object that triggered it
console.log("You triggered a " + evt.type + " on :", evt.target)
// Cancelling an event is generally based on some condition
// Here, we'll make it simple and say that if you click on the
// link when the second is an even second, the navigation will be cancelled
if(new Date().getSeconds() % 2 === 0){
// Normally, clicking a valid hyperlink will navigate you away from the current page
// But, we'll cancel that native behavior by cancelling the event:
evt.preventDefault();
console.log(evt.type + " cancelled! No navigation will occur.");
}
console.log("The mouse was postioned at: " + evt.screenX + " x " + evt.screenY);
console.log("The SHIFT key was pressed at the time? " + evt.shiftKey);
console.log("\tTry clicking again, but with SHIFT held down this time.");
});
Click for NASA
The event property is an object that is passed to every event handler.
This event object then has many properties and methods you can call to manipulate the event process and action in the handler.
For instance, in the event object you have this method called preventDefault() . What does preventDefault() do? Each event is triggered by a particular html dom element in the page. Sometimes this html elements have behaviour attached to them. For instance, and <a> element has the potential of changing the browser url for a particular window. If the element that triggered the event is then an <a>, with preventDefault() you just cut the default behaviour for that <a> anchor and that will avoid an url load/change.
I recommend you find a reference for this event object and pay a read to it. So you'll become more familiar to what it is available within it.
Related
OK this question already has a lot of answers in web, I have read all of them and I don't think any of them fit my situation. After tried like 2 hours I decide to give up and ask the people here:
This is the simplified example: I have a function, which will be triggered by a button click, I will call it click and it has an parameter with it. Inside the click function, I need to add an event listener to the window object use addEventListener().
I need the event to be passed to the handleKeydown(), because I need to know if the shift key (keycode == 16) is pressed down and I need to pass the parameter map to the handleKeydown() because I need to do something on it. after that, there will be more things done, let's say it has a function to draw pictures on the map
So I write the codes below:
function click (map) { // can be called multiple times, so multiple listener are attached, not needed
this.addEventListener("keydown", function(e) {handleKeydown(e, map)}, false)
drawPictureOnMap(map);
}
function deletePictureOnMap() {
// user always call this function to delete the picture before they
// call the click() to draw a new one
// delete the picture on map
}
function handleKeydown(e, map) {
if (e.keyCode == 16) {
// do something to map, e. g.:
// map.getLayers()
}
}
It works all fine until today, I find a big problem with it.
Because the function click can be called multiple times, so I found that multiple event listener are attached to the window object. That has a negative effect on the performance.
The idea is to attach a removeEventlistener() to another function, which is mean to delete the picture on map. Because, the user always delete the picture before they draw a new one.
The Problem is, I can't remove a event listener with anonymous function. But if I want to use external function, I can't find a way to pass the map parameter to it.
Another Idea is, make the map parameter global, so I don't need to pass it to the handleKeydown. But I am not willing to do it.
There are a few ways to solve this. Without more information, the one that comes to mind is this: Maintain a WeakMap of the handlers for a given element (a WeakMap so that if the element is removed and all references to it are dropped, the map entry automatically gets removed). Even IE11 supports WeakMap (enough of it, anyway).
const elementClickHandlers = new WeakMap();
Within that element-to-handlers map, store a Map of the handlers keyed by map.
Then in click, use those maps:
function click (map) { // can be called multiple times, so multiple listener are attached, not needed
let handlers = elementClickHandlers.get(this);
if (!handlers) {
handlers = new Map();
elementClickHandlers.set(this, handlers);
}
let handler = handlers.get(map);
if (!handler) {
handler = function(e) {handleKeydown(e, map)};
handlers.set(map, handler);
}
this.addEventListener("keydown", handler, false)
drawPictureOnMap(map);
}
When removing, find the handler for the element and map and remove that:
const handlers = elementClickHandlers.get(theElement);
if (handlers) {
const handler = handlers.get(map);
if (handler) {
handlers.delete(map);
someElement.removeEventListener("click", handler, false);
}
}
But there may be simpler ways to solve the problem we could suggest, if you showed a proper MCVE.
I am dealing with an odd problem where I need an event handler to bind upon instantiation of a module, but when the module is terminated via a click or a keypress, I no longer want this global event bound. I've gotten the click event to register termination of the module handled elsewhere in code and that works, but the problem is the escape press that I want to globally terminate the module regardless of where my user currently is in the app.
My problem is that the .off() doesn't appear to work given the circumstances.
let tools = {};
//how can i eliminate this next line of code after escape has been triggered?
$(window).on('keydown', (e)=>escape(e, tools));
function escape(e, tools){
if (e.which==27){
//do some stuff with tools, etc
$(window).off('keydown', $(window), escape); //this line doesn't seem to work
alert('alert triggered, but next time escape is pressed it wont.');
}
}
Am I going about this approach wrong? I tried binding it to the div element itself, but this has a whole lot more baggage associated with focussing the div to recieve the keypresses, and if the user navigates to another module, the escape will no longer be triggered because this module will no longer have focus, and well, etc etc etc.
Thank you!
Here is fiddle:
https://jsfiddle.net/rbfebL5y/1/
Use only handler function as argument according to documentation:
let tools = {};
//how can i eliminate this next line of code after escape has been triggered?
$(window).on('keydown', escape);
function escape(e){
if (e.which==27){
//do some stuff with tools, etc
$(window).off('keydown', escape);
alert('alert triggered, but next time escape is pressed it wont.');
}
}
You could use localStorage:
// check key pressed and whether we've done this before
if (e.which==27 && !localStorage.getItem('hasLoggedEscape')){
// set the local storage value saying we've done this before
localStorage.setItem('hasLoggedEscape', 1);
//do some stuff with tools, etc
}
later if you want to reset this, do
localStorage.removeItem('hasLoggedEscape');
I have a question for you regarding this code snippet:
window.location.hash=1;
$(window).on('hashchange', function() {
alert('hello');
});
The script above should do this:
set the location hash to 1
on any further change -> alert('hello')
This is the problem: why is hashchange called at the first time of the first execution? Shouldn't this script change only the hash without any alert?
How can I fix it so that it works as described?
Firstly, you ask:
why is hashchange called at the first time of the first execution? Shouldn't this script change only the hash without any alert?
To answer this, we can delve into the specification. When navigating to a new fragment (ie setting document.location.hash), the specification goes through a number of steps, one of which is:
Traverse the history to the new entry, with the asynchronous events flag set. This will scroll to the fragment identifier given in what is now the document's address.
The specification for traversing the history goes on to say:
If the asynchronous events flag is not set, then run the following steps synchronously. Otherwise, the asynchronous events flag is set; queue a task to run the following substeps.
If state changed is true, fire a trusted event with the name popstate at the Window object of the Document, using the PopStateEvent interface, with the state attribute initialized to the value of state. This event must bubble but not be cancelable and has no default action.
If hash changed is true, then fire a trusted event with the name hashchange at the browsing context's Window object, using the HashChangeEvent interface, with the oldURL attribute initialized to old URL and the newURL attribute initialized to new URL. This event must bubble but not be cancelable and has no default action.
So all of that taken together means that when you run your code, the event listener for hashchange will be added before the code in the substeps of step 14 is run and will subsequently be fired when the hash is set.
How can I fix it so that it works as described?
To fix it, you can also queue the adding of your event listener using setTimeout(.., 0):
setTimeout(function() {
$(window).on('hashchange', function() {
alert('hello');
});
}, 0);
Since you add this to the queue after setting the hash, it will be added to the queue after the task queued in step 14 above, and so the event listener only gets added after the event has been fired.
use a counter inside your code:
var counter = 0;
$(window).on('hashchange', function() {
if (counter)
alert('hello');
counter++;
});
Another way to fix it without calling setTimeout would to register the 'hashchange' event and then set the value of hash.
$(window).on("hashchange",function()
{
alert('Invoked due to hash change' + window.location.hash);
});
alert('Hash Updated');
window.location.hash = "1";
Fiddle : http://jsfiddle.net/86829ryz/10/
Is information about fired events placed into a single Event Object, with each event overwriting any properties of the preceding event? Or are new objects created for each event?
According to W3C DOM4, "Throughout the web platform events are dispatched to objects to signal an occurrence..." and "Events are objects too and implement the Event interface".
The MDN states: "Each event is represented by an object which is based on the Event interface, and may have additional custom fields and/or functions used to get additional information about what happened."
This document "http://web.stanford.edu/class/cs98si/slides/the-document-object-model.html" states "Whenever an event fires, an object is created to represent the event."
This seems to indicate that New Objects based on the Event interface are being created all the time...
Other sources seems to suggest something different. Such as this for example:
"During normal program execution, a large number of events occur, so the event object is a fairly active object, constantly changing its properties.
Whenever an event fires, the computer places appropriate data about the event into the event object - for example, where the mouse pointer was on the screen at the time of the event, which mouse buttons were being pressed at the time of the event, and other useful information."
A new event object is created for each occurrence of an event. In other words, every physical mouse click will dispatch a brand new event object to the click handlers.
The important thing to recognize here is that due to event bubbling and the fact that multiple listeners may be attached to a single element, that one object may be passed in to multiple function invocations. Consider:
el.addEventListener('click', function(e) {
e.foo = 'bar';
});
el.addEventListener('click', function(e) {
alert(e.foo);
});
Since the same event object is passed in to each handler function, the second one will alert bar.
Here's a jsFiddle exploring your question: http://jsfiddle.net/javajunkie314/zpmqndLa/1/
In Chrome 40 at least, the change persists between event handlers while it bubbles, but the change is lost when the next event fires.
The HTML:
<div id="foo">
<div id="bar">Hello</div>
</div>
<div id="baz">World</div>
The JavaScript:
(function () {
var foo = document.getElementById('foo');
var bar = document.getElementById('bar');
var baz = document.getElementById('baz');
foo.addEventListener('click', function (event) {
alert('Foo says: ' + event.testProp);
});
bar.addEventListener('click', function (event) {
event.testProp = 'Hello world!';
alert('Bar says: ' + event.testProp);
});
baz.addEventListener('click', function (event) {
alert('Baz says: ' + event.testProp);
});
})();
I'm trying to execute JavaScript functions that are called when a event (for example onClick event) is performed on a web page with JavaScript code. I'm getting the function from the event like this :
var attributval = document.getElementsByTagName("a").getAttribute('onClick');
and I'm trying to execute this object (which a JavaScript function in fact) as a function (suppose we have <a onClick = alert('whatever');> on this example, I tried:
var attributval = document.getElementsByTagName("a").getAttribute('onClick');
attributval() = function(){attributval};
attributval();
but it didn't work.
A DOM attribute is not the same as a JavaScript property (even though they can have the same name onclick). You should use
var attributval = document.getElementsByTagName("a")[0].onclick;
to retrieve a function (or null) from the JS object (as opposed to getAttribute(), which will most likely return a toString() for the property).
Now, attributval() = is illegal syntax, as attributval() is not an l-value (you cannot assign to it).
attributval(); will work but without the second line (which is illegal JavaScript) it will invoke the original A element onclick handler (if one is defined) or throw an exception (if the onclick handler is null).
Skip trying to create a function around the function. Just call it:
var attributval = document.getElementsByTagName("a")[0].onclick;
attributval();
try
var attributval = document.getElementsByTagName("a")[0].getAttribute('onClick');
By using get attribute you are returning a string so your only way is to use eval(onclickString) or var fn = new Function(onClickString); fn();
attributval is simply a string, correct? If you trust this code, execute it with eval(attributval) -- however any reference to this won't work.
What you probably want is to manually trigger an event. jQuery makes that easy.
If you want to do more than a click, then Chris McDonald's answer at Is it possible to trigger a link's (or any element's) click event through JavaScript? seems to fit the bill, although you might need to heed the third comment.
I thought I'd add a short answer on how to work with events using jQuery, since it seems relevant.
// Select the link using it's ID field (assuming it has one)
var myLink = $('a#myLink')
// Add a click event to the link
myLink.on('click', function(e) {
console.log("I've been clicked!");
});
// Trigger the click event manually. This would result in the above
// function being run. Interestingly, this will not cause the browser
// to follow the link like a real click would
myLink.trigger('click');
// Remove the click event (this removes ALL click events)
myLink.off('click');
// Add a click event to the link that only runs once, then removes itself
myLink.one('click', function() {
alert("I'll only bother you once!");
});
// Add a click event that you can identify from other click events.
// This means that you can trigger it or remove it without bothering other
// click events
myLink.on('click.myClick', function() {
alert("This click event has been identified as 'myClick'");
});
// Now you can trigger it without triggering other click events
myLink.trigger('click.myClick');
// And remove it, also with no harm coming to other click events
myLink.off('click.myClick');
Hope this helps