I have been teaching myself JavaScript over the last Month now, not super consistently since my work has been all over the place, when I get downtime my job is to work on extensions for our sales team.
Right now I don't have a specific issue that i can't solve, but I have a question that makes me think that there is something very different about functions in javascript that I am still missing.
Look at this code, and I will explain what confuses me about it:
function click(e) {
var selection = e.target.id;
}
document.addEventListener('DOMContentLoaded', function () {
var divs = document.querySelectorAll('div');
for (var i = 0; i < divs.length; i++) {
divs[i].addEventListener('click', click);
}
});
So, in this code, I understand what is going on except how the click(e) part. The 'e' is an event object correct? It is not clear to me how that got passed, and how it knows that 'e' means that. I assume I could replace the e with "foo" and it would work still, but exactly what is happening is not clear.
I am pretty sure it has to do with this line of code:
divs[i].addEventListener('click', click);
But I don't understand what is happening behind the scenes to make that happen the way it does.
Another example is this from the message passing at http://developer.chrome.com/extensions/messaging.html:
contentscript.js
================
chrome.extension.sendMessage({greeting: "hello"}, function(response) {
console.log(response.farewell);
});
background.html
===============
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
console.log(response.farewell);
});
});
'response' in this is not clear to me where it is coming from, much like 'e' in the other example. Any help demystifying how this works would be appreciated, I am open to learning, and I haven't found a good explanation about this.
The event object is passed through the function by the browser itself.
In case there is an event and a respective event handler is attached, the browser calls that event handler and passes an event object with some (more or less) relevant information about the event to the event handler.
So with respect to your first example:
First the function click( e ) is defined in a regular way.
Afterwards two event handlers are registered:
for the event DOMContentLoaded
for a click event on multiple <div> elements.
For the first handler an anonymous function is used.
document.addEventListener('DOMContentLoaded', function () {
// do stuff here
});
Here the event object is omitted as it is probably not needed.
In the second case the <div> elements all get the same event handler, namely click(e).
divs[i].addEventListener('click', click);
Here, however, the event object is captured as a parameter by the function as it is needed inside the function body.
In general in JavaScript you don't have to define all parameters either in the function declaration nor in the call of a function. You just define the parameters needed and they are applied in the order given. That's why in the first event handler's definition the parameter for the event object can be omitted without any errors.
The click function is invoked by the browser in response to a click event. The browser passes the appropriate event object as the first argument.
Also, you're correct that e can be anything. You can give the parameter any (legal) name you want.
Related
In javascript we have addEventlister, this listens to an even and calls a function called a listener function. Is an alternate approach possible where we increment the value of a "let variable" without using a function to do this in case of event being triggered?
Instead of this
let clickVar = 0;
x.addEventListener("click", RespondClick);
function RespondClick() {
clickVar++;
}
Sample Alternate implementation
x.addEventListner(click);
if (event == true){ clickVar++; }
======Edit======
Responding to the comment
The more I read this, the more it seems like an XY problem - is there something else you are trying to solve?`
In my view, the second approach is more intuitive. i.e. why create a function unless it's absolutely necessary.
Responding to the comment
There is no logic to how the second approach. The code you write will be executed once. If you want to run code more than once, you have to call a function. In order to run a function when an event happens, you need an event listener.
This simple amendment should take care of the one-time calling problem.
x.addEventListner(click);
if (event == true){ clickVar++; event=false; }
But the point I am trying to make is function could have been avoided, the code could be easy enough to speak, not only write.
Your second sample doesn't work. That simply isn't how event listeners work. You must use a callback function. If you think the first sample is too verbose, you can use an anonymous function:
let clickVar = 0;
x.addEventListener("click", function() {
clickVar++;
});
Or an arrow function in more modern versions of Javascript
x.addEventListener("click", () => {
clickVar++;
});
A few weeks ago I was painfully able to dynamically add buttons to an HTML DOM object that has its own .on('click'.. handler, and use e.stopPropgation to stop these new child elements from firing the event.
The weird thing I did was call a function without any parenthesis. I have no idea why I did this or why it works, or why it does not work when I do attach parenthesis. I want to know if I am doing something by fluke and not design (and now I will add comments to it).
It goes as such:
//Container is the parent element
// var buttons stores the buttons with class 'buttons'
$('.container').on('click', function(){
$(buttons).appendTo($(this)).fadeIn(500).find('.buttons').click(tableButton);
});
function tableButton(e){
e.stopPropagation();
//do stuff
}
I can't figure out why I wrote the call to tableButton with no arguements or why it works perfectly. I tried to change the syntax to
.find('.buttons').on('click', function(e){
tableButton(e);
});
but then it no longer works.
Any help appreciated!
It works because you're passing a function to the click handler rather than calling the function yourself (the ()) An example of that:
var testFunction = function(msg) {
alert(msg);
}
var functionCaller = function(functionToCall) {
functionToCall('hello!');
}
functionCaller(testFunction);
functionCaller passes the message argument to testFunction(), but we only pass testFunction to functionCaller (without arguments)
For the part which doesn't work, isn't the function name tableButton() instead of tableButtons()?
See http://jsfiddle.net/g2PAn/
You don't actually call it, you just declare it and the arguments it accepts. The click callback is called with an argument indeed, but not by you.
The problem probably comes from the fact that jQuery calls your function with the element clicked bound as this, you could call table button like this:
.find('.buttons').on('click', function(e){
tableButton.call(this, e);
});
I am taking a web development class. Today the teacher gave us a piece of code that raised some questions that I haven't been able to satisfactorily solve through my own searching. The code in question was essentially this:
<script>
function selectmouse(e){
...
...
}
document.onmousedown = selectmouse;
</script>
My first question, is this a legitimate way of calling functions? Is this something that is done? I am of course familiar with the typical way of calling functions from HTML elements, for example
<body onmousedown="selectmouse(event)">
The code was supposed to be calling the function and passing it the event object for the onmousedown. After playing with the code for a while I found a few unusual things.
First, if I put parenthesis after the function call, like I am used to doing (i.e. selectmouse();), then the function resolved immediately upon loading the page, with a value of 'undefined' for the variable. This makes intuitive sense to me, because I assume the browser is treating it like a variable assignment and therefore calling the function as it parses the code, as it normally would to assign a variable.
However the part that is weird to me happened when I deleted the '()' and left it as it is coded above. In this instance it seemed to function like she wanted it to. It would call the function when the mouse was pressed in any part of the body, and it sent the event object as the variable for the function. But I can't figure out why. I can't find reference to anything similar to it online, and I've never seen anything like it before. Is this a legitimate way to do something like this? Or is this bad code that happens to be working for some reason and would probably cause problems in the future? Why is it working?
document.onmousedown = selectmouse; //note: never do this except in old browsers
However the part that is weird to me happened when I deleted the '()' and left it as it is coded above. In this instance it seemed to function like she wanted it to.
That's not weird. You are passing the reference of the function to the browser, not executing it.
For example, you have this function:
function callback(){
alert("clicked!");
}
document.body.onclick = callback;
You pass the reference to onclick and the browser will know what function to call when the event is triggered. But if you do it like this:
document.body.onclick = callback();
This will be evaluated into:
document.body.onclick = alert("clicked!");
//Note that this is simplified explanation to visualize what is happening.
//The returned value of alert() is not assigned to onclick.
//To be exact the returned value of callback() is the one that is being assigned.
//Similar to:
// ...onclick = (function(){ alert("clicked!"); })();
Then you will see an alert, and the browser will continue executing the rest of the code:
document.body.onclick = undefined;
<body onmousedown="selectmouse(event)"> <!-- Don't do this too -->
The parentheses are necessary because this code is not executed instantly. It is only executed when the event is triggered.
Anyway, you shouldn't attach events both using .onmousedown or onmousdown="...". There is a better way of doing it:
element.addEventListener("mousedown", callback, false);
Reason: If you use the onmousedown property, you can only attach one mousedown event. In most cases you would want to attach more than one.
Also attaching events inline might cause security problems (cross-site scripting), and that is exactly why Google decided to prohibit all developers from using them in developing Chrome apps/extensions.
This is legitimate code and is working as it should.
The way you are comfortable with is just a method we tried while the web was evolving, but at present we should better use the second way you showed, although its changed bit more to make you understand it in a better way using event bindings.
When you do
function selectmouse(e){
...
...
}
javascript will create a variable named selectmouse and save the function in that variable. So selectmouse is a variable of type function with the function body as its value.
document on the other hand can be related to class or specifically an object which is an instance. Each document and each HTML element or DOM node can have in it variables to store the functions to be called on user events like onmousedown.
so when doing
document.onmousedown = selectmouse;
we are inturn saying
when mousedown happens in document, the function named selectmouse
should be called
If you do
document.onmousedown = selectmouse();
it means
run the function selectmouse immediately and get the result, assign
the result to onmousedown event of the DOM Node document.
And if you ask why this is taken apart from the form
<body onmousedown="selectmouse(event)">
To answer in a simple way, HTML is Hyper Text Markup Language, its sole purpose is to represent formatted data, the quick evolution of web inturn made it deranged with behaviours like this and presentation code like inline css. So to make behaviour and presentation out of HTML and thus a better design we do this.
Please take time to take a look at how you can bind a function to an event which is the current tradeoff in doing this same thing.
For a detailed explanation please check the events sectio of ppk blog here
I think that is correct, because the function is being called within the script as if it were an object, to me is not the best way to do it, I would have like this (with jquery):
$(document).mousedown(function (event) {
// here the content of the function
});
<body onmousedown="selectmouse(event)">
In this example the browser evaluates the result of the expression selectmouse(event) and assigns it to the onmousedown property of the body, event is undefined and the selectmouse doesn't return anything so it's result is undefined.
It is equivalent of the following if it was inside a script tag
<script>
function selectmouse(e) {
}
document.body.onmousedown = selectmouse(event);
</script>
<body onmousedown="selectmouse">
When you remove the () you are assigning a function to the onmousedown property. Now the browser fires your callback method whenever the mousedown event is raised and it bubbles up to the body, passing the current event as the parameter you're declaring as "e". If another element also had an onmousedown event handler declared but it cancelled the event ( by calling event.cancelBubble = true ) the body's onmousedown handler will not be invoked.
<script>
function selectmouse(e) {
}
document.body.onmousedown = selectmouse;
</script>
This should be an easy one :)
I want to add a click event listener only in case it hasn't been added earlier already, and prevent it from running twice. I thought of accomplishing this like so:
HTML
Google is your friend
Bing's alright as well
JS
var links = document.getElementsByTagName("a");
for (var i=0; i<links.length; i++)
{
if (*Default has been prevented for links[i]*){ //how do I implement this check?
return; //do nothing, we're all done.
} else {
links[i].addEventListener("click",function(event){
event.preventDefault();
alert("Showing you this instead of opening this link!");
});
}
}
In my real world case the added event listener is preventing the default behavior. So how can I check if it has been prevented before? I want to make sure the listener won't be added twice. How can I implement this check?
Many thanks for any ideas.
You can achive your goal using object identity. Quote from MDN:
Multiple identical event listeners
If multiple identical EventListeners are registered on the same
EventTarget with the same parameters, the duplicate instances are
discarded. They do not cause the EventListener to be called twice, and
since the duplicates are discarded, they do not need to be removed
manually with the removeEventListener method.
Example:
// the "one" handler function instance
var theEventPreventDefaultHandler = function (event) {
event.preventDefault();
};
var links = document.getElementsByTagName("a");
for (var i = 0; i < links.length; i++) {
links[i].addEventListener("click", theEventPreventDefaultHandler);
}
Watch the Fiddle.
I didn't check that out, but it could be possible the addEventListener function returns false to catch the case, when it didn't add a "duplicate". It doesn't, returns only undefined.
To "check if an event has a handler" is not supported natively. It is possible in jQuery, because this manages the handlers in a .data("events") array, also to support IE's old quirks behaviors in this and window.event. That said, it would be a pain in the ass to reimplement what ejohn did. There about are a bunch of questions on stackoverflow:
test if event handler is bound to an element in jQuery
Answer on "How to check if click event is already bound - JQuery"
... google "jquery check bound event"
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