I need to execute code from 3 different places on my website when an event gets triggered. I've added 3x listeners but for some reason only the first listener gets called.
Here's the code I'm testing at the moment: JSFiddle
window.addEventListener('tompina_event', function (e) {
document.write("triggered 1");
});
window.addEventListener('tompina_event', function (e) {
document.write("triggered 2");
});
window.addEventListener('tompina_event', function (e) {
document.write("triggered 3");
});
var evt = new CustomEvent('tompina_event');
window.dispatchEvent(evt);
Result:
triggered 1
This is the result I was hoping for:
triggered 1triggered 2triggered 3
It works, but the document.write destroys the original page and thus the execution of other code.
Please rewrite so the result is set in an other way like alert("triggered 1") or console.log("triggered 1").
The problem is with document.write(). Each call is overriding the strings from the previous call, and it appears that only one is firing. Change to console.log(), or document.body.innerHTML += "" and you will see them all firing.
The write() method is mostly used for testing: If it is used after an HTML document is fully loaded, it will delete all existing HTML.
Related
Out of curiosity if I am using for example.
window.onload = function() {
testFunction();
};
function testFunction() {
alert("Hello World!");
}
Does this pause the script or simply waits till the window load value is true and run the statement? I am sure its the latter but to better understand script behavior I was curious to find answer with more knowledgeable coders.
window.onload = ... is just an assignment: it stores a function in the window.onload variable. When an event happens, the JavaScript engine looks at the corresponding onsomething property and runs the function assigned to that variable. In fact, this would be valid as well:
function testFunction() {
alert("Hello World!");
}
window.onload = testFunction;
The same thing is true for functions bound with the addEventListener function.
window.addEventListener("load", function(e) {
// do something
});
window.addEventListener("load", function(e) {
// do something else
});
This simply adds functions to an underlying list of functions which will be called when the load event happens. This is required when you need to bind multiple events to the same object.
It's an event listener.
See documentation here: http://www.w3schools.com/js/js_htmldom_events.asp
and here:http://www.w3schools.com/js/js_htmldom_eventlistener.asp
You might like to try the Visual Event extension for Chrome. It shows you all event listeners that are currently attached to the page displayed.
I have a question regarding the order of execution of JavaScript (listener) methods. While I appreciate the below code is probably not best practise, is there any way to guarantee the order the below functions will fire when btn1 is changed?
$(function() {
$('#btn1').change(function(){
doStuff();
});
});
$(function() {
$(#btn1, btn2).change(function(){
doMoreStuff();
});
});
E.g. is it possible to assert that based on the order the JS code "appears in" (i.e listed in the actual js / html file), that (when #btn1 changes):
1. that doStuff() will execute first
2. that doStuff() will complete fully before doMoreStuff() is invoked – assuming all doStuff is doing is updating the DOM
I have a real example, where doStuff updates the DOM and doMoreStuff invokes an Ajax endpoint, using the updated DOM values - and want to be sure doStuff will always be invoked first (again based on the flaky design that it is "listed" first).
Thanks,
Damien
As far as I'm aware, jQuery ensures event handlers fire in the order in which they were created (first in, first out). Currently I can't find any documentation on this, but I'm sure I have read that somewhere in the past.
As long as your first change function isn't asynchronous, it should be the case that the first function will finish execution before the second starts. We can test this by adding a loop within our first change function:
$(function() {
$('#btn1').change(function(){
console.log("First change event triggered at " + +(new Date()));
for (var i = 0; i < 100000000; i++)
continue;
console.log("First change event finished at " + +(new Date()));
});
});
$(function() {
$('#btn1, #btn2').change(function(){
console.log("Second change event triggered at " + +(new Date()));
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<select id="btn1"><option>1</option><option>2</option></select>
<select id="btn2"><option>1</option><option>2</option></select>
As you can see, the first finishes before the second starts.
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 would like the specified function to be called only if the correct button is clicked on.
function callback(func){
func();
}
The main function(s) and their results:
Attempt A:
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('num1').addEventListener('click', callback(function1));
document.getElementById('num2').addEventListener('click', callback(function2));
});
Result: Opening the page and clicking any of the buttons will run function1
Attempt B:
document.addEventListener('click', function () {
document.getElementById('num1').addEventListener('click', callback(function1));
document.getElementById('num2').addEventListener('click', callback(function2));
});
Result: Clicking anywhere on the page will run function1
Attempt C:
document.getElementById('num1').addEventListener('click', callback(function1));
document.getElementById('num2').addEventListener('click', callback(function2));
Result: Opening the page and clicking on the buttons will run function1 and reload the page
Attempt D:
document.addEventListener('click', function () {
//The first ID doesn't exist
document.getElementById('imaginaryNum1').addEventListener('click', callback(function1));
document.getElementById('num1').addEventListener('click', callback(function1));
document.getElementById('num2').addEventListener('click', callback(function2));
});
Result: Clicking anywhere on the page will run function1
Attempt E:
//The first ID doesn't exist
document.getElementById('imaginaryNum1').addEventListener('click', callback(function1));
document.getElementById('num1').addEventListener('click', callback(function1));
document.getElementById('num2').addEventListener('click', callback(function2));
Result: Opening the page and clicking on the buttons will run function1 and reload the page
Sure, why wouldn't it be. Looking at your code, though, you might be better of delegating the event: it's not that hard. Basically, listen for the event you need on a level in the dom that contains each of the individual elements, and write your handler in such a way that you check if the element that fired the event is of interest, if so: handle the event, if not, just return. You're also missing the third argument, that addEventListener expects: a boolean, indicating weather you want to handle the event during the capturing phase, or the bubbling phase, read a couple of articles on quirksmode, in particular on the distinct phases
I've also noticed that you're doing weird things with your handler function, you're going to have some issues with that. Basically, what addEventListener expects as a second argument is a reference to a function, you're passing the return value of a function (which is undefined in your case).
function clickHandler(e)//accept event argument
{
e = e || window.event;
var target = e.target || e.srcElement;
if (!target.id.match(/num[0-9]/))
{//the clicked element doesn't have num1, num2, num3... as id, no need to handle this event
return e;
}
//handle event. target is a reference to the clicked element
}
document.body.addEventListener('click',clickHandler,false);//<-- just the function name, no parentheses
That's all you need, one listener that'll handle all click events.
Here are a couple of JS questions that I've posted that deal with event delegation, take a look at the code, read the articles I linked to, you'll soon work it out.
delegating the change event in IE -- tricky
avoid mem-leaks in IE<9 with onload listener: my answer to the question
Augmenting the event prototype in IE<9 using delegation
callback immediately executes the function that is passed into it - so it is never passed to the addEventListener - instead, undefined is passed.
.addEventListener('someEvent', callback(functionN), false) is essentially .addEventListener('someEvent', (function(){ functionN() })(), false).
Change to .addEventListener('someEvent', functionN, false) and see what happens - if you are still getting errors take a look in the Script Panel of your web browser and see what errors are being generated.
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.