Javascript for loop function closure printing out of order [duplicate] - javascript

This question already has answers here:
Coordinating parallel execution in node.js
(7 answers)
Closed 5 years ago.
I am implementing the IIFE method when wrapping a for a loop around an async/ajax call.
var j = 4;
for (var i = 0; i < j; i++) {
(function(cntr) {
asyncCall(function() {
console.log(cntr);
});
})(i);
}
The problem is that when I console.log cntr, I get all of the values, but they have a random order. Let's say I have a for loop from 0-4. It will print these values in a random order, like 2,1,3,4,0. This changes every time I rerun the code.
Edit:
The question linked to most certainly is not the answer. Please pay more attention before marking as duplicate. I'm also not even using nodejs...

Your asyncCall doesn't finish in a constant amount of time. Since you begin each asynchronous call within a synchronous for-loop, whichever call finishes first will log first (in other words, the calls do not wait for each other).
There are two ways to go about fixing this problem. The first is to wait for each asyncCall to complete before beginning the next, which you could do easily with recursion:
var calls = 4
var i = 0
asyncCall(function handler() {
console.log(i)
if (++i < calls) asyncCall(handler)
})
function asyncCall(handler) {
setTimeout(handler, 0)
}
This approach makes the most sense if each successive call depends on the result of the previous call, which yours might not. In that case, it is more efficient to have each call execute up-front, but store the results in an array which you log once every call has completed:
var calls = 4
var done = 0
var i = 0
var results = []
for (var i = 0; i < calls; i++) (function(i) {
asyncCall(function handler() {
results[i] = i // example data
if (++done === calls) complete()
})
})(i)
function complete () {
// Do something with your array of results
results.map(function (e) {
console.log(e)
})
}
function asyncCall(handler) {
setTimeout(handler, Math.random()*10)
}

A self-executing closer, which it looks like you're looking for, is used like this:
//<![CDATA[
/* external.js */
var doc, bod, htm, C, T, E; // for use onload elsewhere
addEventListener('load', function(){
doc = document; bod = doc.body; htm = doc.documentElement;
C = function(tag){
return doc.createElement(tag);
}
T = function T(tag){
return doc.getElementsByTagName(tag);
}
E = function(id){
return doc.getElementById(id);
}
addClassName = function(element, className){
var rx = new RegExp('^(.+\s)*'+className+'(\s.+)*$');
if(!element.className.match(rx)){
element.className += ' '+className;
}
return element.className;
}
removeClassName = function(element, className){
element.className = element.className.replace(new RegExp('\s?'+className), '');
return element.className;
}
var outs = doc.getElementsByClassName('output');
for(var i=0,out,l=outs.length; i<l; i++){
(function(){
var out = outs[i], b = false;
out.onclick = function(){
if(b){
removeClassName(out, 'blue'); b = false;
}
else{
addClassName(out, 'blue'); b = true;
}
}
}());
}
}); // close load
//]]>
/* external.css */
html,body{
padding:0; margin:0;
}
.main{
width:980px; margin:0 auto;
}
.output{
width:100px; border:1px solid #000; border-top:0;
}
.output:first-child{
border-top:1px solid #000;
}
.blue{
background:lightblue;
}
<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
<head>
<meta http-equiv='content-type' content='text/html;charset=utf-8' />
<link type='text/css' rel='stylesheet' href='external.css' />
<script type='text/javascript' src='external.js'></script>
</head>
<body>
<div class='main'>
<div class='output'>Sorry</div>
<div class='output'>This</div>
<div class='output'>Example</div>
<div class='output'>Isn't</div>
<div class='output'>Better</div>
</div>
</body>
</html>
Here's how the closure works. Events actually fire when they occur, like onclick. By the time the Event fires you are actually at the end of the loop, so when that happens, vars and arguments look for the level they were last scoped to.

Related

Javascript - GUI programming

When the selection of the dropdown does change, I would like to:
1) show some GUI blocking overlay via a div over the whole website
2) then process some code
3) then hide the overlay.
The problem is that when I write this logic in the eventlistener-function then onChange 2) would execute, then the GUI performs the updates of 1) and 3), because the GUI is only updating in Javascript when all functions are executed. That's not the correct order and not what I want.
So I thought I introduce a Webworker, but it turned out that the Webworker does exeactly nothing, the order is still wrong.
demo_workers.js:
postMessage("show_overlay_runtime");
postMessage("do_stuff");
postMessage("hide_overlay_runtime");
<!DOCTYPE html>
<html>
<head>
<style>
#overlay {
position: absolute;
top:200px;
left:0;
background-color: #000;
display:none;
width:100%;
height:200px;
}
</style>
</head>
<body>
<div id="overlay"></div>
<select id="my_dropdown">
<option>option1</option>
<option>option2</option>
</select>
<script>
let my_dropdown = document.getElementById('my_dropdown');
my_dropdown.addEventListener('change', function (e) {
dropdown_network_change_response();
}, false);
var workers = {};
function dropdown_network_change_response()
{
let worker_name = "worker1";
startWorker(worker_name, "demo_workers.js");
workers[worker_name].onmessage = function(event) {
if(event.data === "show_overlay_runtime") {
document.getElementById('overlay').style.display = "flex";
}
else if (event.data === "do_stuff") {
for(let i = 0; i < 1000000; i++) {
}
}
else if (event.data === "hide_overlay_runtime") {
document.getElementById('overlay').style.display = "none";
}
alert("test");
};
}
function startWorker(worker_name, file) {
if(typeof(Worker) !== "undefined") {
if(typeof(workers[worker_name]) == "undefined") {
workers[worker_name] = new Worker(file);
}
} else {
document.getElementById("result").innerHTML = "Sorry! No Web Worker support.";
}
}
function stopWorker(worker_name) {
workers[worker_name].terminate();
workers[worker_name] = undefined;
}
</script>
</body>
</html>
So how can I achieve what I mentioned above in Javascript?
You can use setTimeout to give the GUI a chance to do its updating before certain code starts; for example:
function afterGUIupdate() {
postMessage("do_stuff");
postMessage("hide_overlay_runtime");
}
postMessage("show_overlay_runtime");
setTimeout( afterGUIupdate, 1 );
Technically, your code finishes after calling setTimeout, so the GUI can do its updating. Then the timeout kicks in, executing the code you want to occur after that.

How can I make javascript function to wait for other function to finish without using any external APIs?

I have a function that calls other function containing setinterval. Depending on variables, the second function needs varying amount of time to complete. If first function continues before second ends, hell happends.
The question is, how can I make first function wait for the second function to complete before proceeding with next line. I'm not allowed to use any external APIs. Thanks.
Heres the code but it may be a little hard to understand.
HTML:
<html>
<head>
<style>
#canvas {
background-color: rgba(158, 167, 184, 0.2); }
</style>
</head>
<body onload="room1();">
<canvas id="canvas" style="border: none;" width="800" height="600"></canvas>
<script src="main.js"></script>
</body>
</html>
JS:
var canvas=document.getElementById("canvas");
var gra=canvas.getContext("2d");
gra.font = "20px Courier New";
function pisz(text,x,y, interval) {
x1=x;
var i=0;
var stopPisz=setInterval(function(){
if (i<text.length) {
var audio = new Audio('typwriter.wav');
audio.volume=.1;
if (i%3==0 && text[i]!=" ") audio.play();
gra.fillText(text[i],x1,y);
x1=x1+12;
if (x1>700 && text[i]==" "){
x1=x;
y=y+22;
}
}
if (i>text.length-2) clearInterval(stopPisz);
i++;
},interval);
}
function room1 () {
text1="Witam cię w mojej grze. Twoim zadaniem jest rozwiązanie zagadek i wydostanie się z labiryntu pokoji.";
text1.split("");
pisz(text1,20,30,50);
text2="gfhfdghd hg fdhfgdfdf fdhfdgdfdf hdgdfhdfgdfghd";
text2.split("");
pisz(text2,20,200,50);
}
I want to achieve something like this:
function f1 () {
function f2(/*some parameters*/ );
//wait for function f2 to end, then proceed to next line of this function
function f2(/*some parameters*/);
//wait, etc.
}
function f2(/*some parameters*/){
//doing something once
setInterval(function(/*some parameters*/){
//repeating something for some time, then clearInterval so the function ends
},some interval);
}
Why you didn't use callBacks?
You can pass any callBack as a function to another function, and call it whenever you want, for example, on http response or after timeOut, or in specific step of interval.
var f1 = function(delay, cb) {
setInterval(function() {
// do whatever you want, and now it's time to call your second function
if (cb) cb();
}, delay);
}
var f2 = function(param) {
console.log('second function', param || '---');
}
// Use like this:
f1(1000, f2);
// or :
f1(2000, function() {
console.log('second function will be call');
f2('with param');
});

How to call my main function of JS to my html?

I have nested function in function of JavaScript and I want to call it in my main function photoGallery() of my html code, but didn't work. Where I'm wrong ?
JavaScript:
function photoGallery1() {
kartinki = new Array('images/green_salad1.png', 'images/green_salad2.png', 'images/green_salad3.png');
index = 0;
function next() {
index++;
if ( index >= kartinki.length) index = 0;
document.getElementById('image2').src = kartinki[index];
}
function previous() {
index--;
if ( index < 0) index = kartinki.length -1;
document.getElementById('image2').src = kartinki[index];
}
function start() {
index = 0;
document.getElementById('image2').src = kartinki[index];
}
}
The HTML code:
<!Doctype html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="viewport" content="width=device-width">
<meta charset="utf-8">
<title>The right eating of employed people</title>
<link rel='stylesheet' media='screen and (max-width: 1000px)' href='css/narrow.css'/>
<link rel='stylesheet' media='screen and (min-width: 1001px) and (max-width: 1235px)' href='css/medium.css' />
<link rel='stylesheet' media='screen and (min-width: 1236px)' href='css/wide.css' />
<link rel="stylesheet" href="css/calendarview.css">
<script src="js/photogallery.js"></script>
<script src="js/prototype.js"></script>
<script src="js/calendarview.js"></script>
<script type="text/javascript">
window.onload = function() {
Calendar.setup({
parentElement : 'calendar'
})
window.onload = photoGallery1()
}
</script>
First:
window.onload = photogallery1();
Results in an undefined value for the window.onload property.
As #mrbinky3000 said, you need to call photogallery1() in your onload event handler.
Furthermore, you need an object with public methods in order to make this accessible from an outside scope, in which case you need a Constructor Function:
function Photogallery() {
// Don't forget the "var" directive to prevent these from being global
var kartinki = new Array('images/green_salad1.png', 'images/green_salad2.png', 'images/green_salad3.png');
var index = 0;
this.next = function () {
index++;
if ( index >= kartinki.length) index = 0;
document.getElementById('image2').src = kartinki[index];
}
this.previous = function () {
index--;
if ( index < 0) index = kartinki.length -1;
document.getElementById('image2').src = kartinki[index];
}
this.start = function () {
index = 0;
document.getElementById('image2').src = kartinki[index];
}
}
Now your onload changes a little:
var photoGallery = null;
window.onload = function () {
// the other stuff you had
photoGallery = new Photogallery();
}
Don't forget to declare the photoGallery variable to avoid it being an implicitly declared global variable.
Now a little HTML to call the methods on your object:
<button type="button" onclick="photoGallery.next()">Next</button>
<button type="button" onclick="photoGallery.previous()">Previous</button>
I think this is what you were going for. That window.onload = photoGallery1() inside of the window.onload callback made no sense to me.
window.onload = function() {
Calendar.setup({
parentElement : 'calendar'
});
photoGallery1();
}
This will call the photoGallery1() function when the window.onload event fires. There are a lot of issues, however, with your script. Lots of things to improve.
First of, you are assigning the executed photoGallery1() function to window.onload, so basically the result of photoGallery1(). You need to assign the function itself:
window.onload = photoGallery1;
In your function photoGallery1() there is no functions being executed or returned. When we refer to scope, it means where certain functions and variables is visible from.
If you look at the functions inside photoGallery1, they are inside the scope of photoGallery1 and can not be accessed or executed from the outer scope.
One possible solution would be to do:
function photoGallery1() {
function start() {
// do your things
}
// invoke function
start();
}
window.onload = photoGallery1;
Another is to expose some of your funnctions by returning some of the functions that you need:
function photoGallery1() {
function start() {
// do your things
}
function next(){};
function previous(){};
return {
start: start,
next: next,
previous: previous
}
}
// Execute your functions
var photoGallery = photoGallery1();
window.onload = photoGallery.start;
photoGallery1() should be instantiated
var Gallery = new photoGallery1();
Functions you declared in the body of photoGallery1() are private, so you have to attach them to events inside photoGallery1.
You can look at the function as the Class and Constructor in one. So use it accordingly.
I'm not exactly sure what you are trying to accomplish, but if it is a photo gallery like my common sense would indicate, then these three things may help.
Remove any superfluous information from your example, as it confuses the issue you are trying to solve. (f.e. the calendar.js and CSS stylesheet calls). This will allow others to help you in a more effective manner.
Separate your function from your form. It is generally good practice to use HTML strictly for the skeleton of the web page/app and keep the abilities of the skeleton (the functions the page/app can do) in the javascript. This is demonstrated in my example.
Instead of nesting functions try turning your "photogallery" into an object and assigning the "next", "previous", and "start" methods to the appropriate event. (In my example I assigned "next" and "previous to buttons and "start" to window.onload)
The External Javascript File: "photogallery.js"
/*
* Wrapping code in an iife is always good practice to prevent the pollution of the global
* name space.
*/
(function(){
/*
* Declare your array of images and index outside of the photoGallery1 object so the
* methods of photoGallery1 can cleanly reference them before photoGallery1 is initialized
* in the global execution context
*/
var kartinki = ['images/green_salad1.png', 'images/green_salad2.png', 'images/green_salad3.png'];
var index = 0;
var photoGallery1 = {
next: function (){
index++;
/*
* Here the index will never be greater than kartinki.length so check against
* (kartinki.lenghth - 1) or use index == kartinki.length
*/
if (index > (kartinki.length - 1)) { index = 0 };
document.getElementById('image2').src = kartinki[index];
},
previous: function() {
index--;
if ( index < 0) { index = kartinki.length - 1 };
document.getElementById('image2').src = kartinki[index];
},
start: function() {
document.getElementById('image2').src = kartinki[index];
}
}
/*
* Do the below inside an external javascript file rather than the html you can set the
* window object's onload property to an anonymous function, in which you can call any
* functions you want to happen when the page loads (i.e. photoGallery1.start() is called).
*/
window.onload = function(){
photoGallery1.start()
}
//Setting the "next" and "previous" methods to there corresponding buttons
document.getElementById('prev').onclick = photoGallery1.previous
document.getElementById('next').onclick = photoGallery1.next
})()
The HTML file: "index.html"
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>The right eating of employed people</title>
</head>
<body>
<img id="image2">
<button id="prev">Previous</button> <button id="next">Next</button>
<!-- Add the script tag at the bottom of the body so the browser can render the
html elements referenced in photogallery.js before they are needed. If you don't do
this document.getElementById("image2") will return null, as it has not been created
at the time of photogallery.js's execution.
-->
<script src="/photogallery.js"></script>
</body>
</html>
If you have any questions please don't hesitate to ask! :D
If I got, you want the 3 functions inside photoGallery1() to be called only when photoGallery1() is called. If it is the point, just call them at the end before to close.
function photoGallery1() {
kartinki = new Array('images/green_salad1.png', 'images/green_salad2.png', 'images/green_salad3.png');
index = 0;
function next() {
index++;
if ( index >= kartinki.length) index = 0;
document.getElementById('image2').src = kartinki[index];
}
function previous() {
index--;
if ( index < 0) index = kartinki.length -1;
document.getElementById('image2').src = kartinki[index];
}
function start() {
index = 0;
document.getElementById('image2').src = kartinki[index];
}
next();
previous();
start();
}
Thank you to all for the helping and tips! :) Already is working fine and how I wanted! Lastly I post the final codes.
HTML:
<!Doctype html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="viewport" content="width=device-width">
<meta charset="utf-8">
<title>Правилното хранене на заетите хора</title>
<link rel='stylesheet' media='screen and (max-width: 1000px)' href='css/narrow.css'/>
<link rel='stylesheet' media='screen and (min-width: 1001px) and (max-width: 1235px)' href='css/medium.css' />
<link rel='stylesheet' media='screen and (min-width: 1236px)' href='css/wide.css' />
<link rel="stylesheet" href="css/calendarview.css">
<script src="js/photogallery.js"></script>
<script src="js/prototype.js"></script>
<script src="js/calendarview.js"></script>
<script type="text/javascript">
window.onload = function() {
Calendar.setup({
parentElement : 'calendar'
})
photoGallery = new Photogallery();
}
</script>
<body>
......
<p id="photogallery">
<img src="images/prev.png" border="0"><img src="images/home.png" border="0" onclick="photoGallery.start()"><img src="images/next.png" border="0">
</p>
....
</body>
</html>
JavaScript code:
function Photogallery() {
var kartinki = new Array('images/green_salad1.png', 'images/green_salad2.png', 'images/green_salad3.png');
var index = 0;
this.next = function () {
index++;
if ( index >= kartinki.length) index = 0;
document.getElementById('image2').src = kartinki[index];
}
this.previous = function () {
index--;
if ( index < 0) index = kartinki.length -1;
document.getElementById('image2').src = kartinki[index];
}
this.start = function () {
index = 0;
document.getElementById('image2').src = kartinki[index];
}
}
var photoGallery = null;
window.onload = function () {
photoGallery = new Photogallery();
}

Javascript cannot see dynamically generated elements?

I don't know why the newly generated elements can't be seen by next called function? Thanks for help!!
Solution: Add async: false to disable asynchronous feature to make sure test-output-2 and test-output-3 executed after birth process. By default, ajax uses async: true that is sth like multi-threading.
function birth(mom)
{
$.ajax(
{url: "/cgi-bin/count.cgi", // return 3 for sure
async: false, // add this to disable asynchronous feature to make sure test-output-2 and test-output-3 executed after birth process
success: function(xkids) // xkids is 3
{
for( var i = 0; i < xkids; i++ )
{
mom.appendChild(document.createElement("div"));
mom.children[i].setAttribute("id", "child-"+i);
}
document.getElementById("test-output-1").innerHTML = mom.children.length; // now there are 3 children
}
});
document.getElementById("test-output-2").innerHTML = mom.children.length; // there are 0 children if async: true
}
var marry = document.getElementById("Marry"); // currently no child
birth(marry);
function whereIsTheChildren()
{
document.getElementById("test-output-3").innerHTML = marry.children.length; // there are 0 children if async: true
}
whereIsTheChildren();
Trying to locate an element in the DOM before it's loaded won't work (the script runs as soon as its encountered. If this is above the html in the file, the element wont exist yet and thus, wont be found)
Similarly, firing off an AJAX request and then acting as though this was a synchronous operation (waits for the operation to finish before executing more code) will not work.
In the first instance, the code is encountered before the browser has had time to parse the HTML, thus the element doesn't exist in the DOM when you try to get a reference to it - this can be fixed by waiting for the document to signal that it's completed loading.
The second issue is that immediately after firing the birth function, the whereIsTheChildren function is fired. Unfortunately, the ajax request is still pending and so we've not got the results back from it yet that we need to use. This is fixed by putting the call to whereIsTheChildren inside the success call-back for the ajax request.
I've whipped up a quick example, using vanilla JS and PHP - just substitute the request to the php file with the one for your CGI.
getKidCount.php
<?php
echo "3";
?>
index.html
<!doctype html>
<html>
<head>
<script>
"use strict";
function byId(id,parent){return (parent == undefined ? document : parent).getElementById(id);}
function myAjaxGet(url, successCallback, errorCallback)
{
var ajax = new XMLHttpRequest();
ajax.onreadystatechange = function()
{
if (this.readyState==4 && this.status==200)
successCallback(this);
}
ajax.onerror = function()
{
console.log("AJAX request failed to: " + url);
errorCallback(this);
}
ajax.open("GET", url, true);
ajax.send();
}
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(evt)
{
//birth(3, byId("Marry") );
myBirth( byId('Marry') );
}
function myBirth(parentElem)
{
myAjaxGet('getKidCount.php', onAjaxSuccess, onAjaxFail);
function onAjaxSuccess(ajax)
{
var numKids = parseInt(ajax.responseText);
for (var i=0; i<numKids; i++)
{
var div = document.createElement('div');
div.id = ("child-"+i);
parentElem.appendChild(div);
}
document.getElementById("test-output-1").innerHTML = parentElem.children.length; // now there are 3 children
whereIsTheChildren();
}
function onAjaxFail(ajax)
{
alert("Ajax failed. :(");
}
}
function whereIsTheChildren()
{
document.getElementById("test-output-2").innerHTML = byId('Marry').children.length; // there are 0 children
}
/*
function birth(xkids, mom)
{
for( var i = 0; i < xkids; i++ )
{
mom.appendChild(document.createElement("div"));
mom.children[i].setAttribute("id", "child-"+i);
}
document.getElementById("test-output-1").innerHTML = mom.children.length; // now there are 3 children
}
function birth(mom)
{
$.ajax(
{url: "/cgi-bin/count.cgi", // return 3 for sure
success: function(xkids) // xkids is 3
{
for( var i = 0; i < xkids; i++ )
{
mom.appendChild(document.createElement("div"));
mom.children[i].setAttribute("id", "child-"+i);
}
document.getElementById("test-output-1").innerHTML = mom.children.length; // now there are 3 children
}
document.getElementById("test-output-2").innerHTML = mom.children.length; // now there are 0 children
}
*/
</script>
</head>
<body>
<div id='test-output-1'></div>
<div id='test-output-2'></div>
<div id='Marry'></div>
</body>
</html>
Modified to represent in DOM as well is in console.log
function birth(xkids, mom) {
var mom = document.querySelector(mom);
console.log('Mom: '+mom.id);
for (var i = 0; i < xkids; i++) {
mom.appendChild(document.createElement("div"));
mom.children[i].setAttribute("id", "child-" + i);
mom.children[i].innerHTML = mom.children[i].id;
}
console.log(mom.id+' has '+mom.children.length+' children');
var test = document.createElement("output");
document.body.appendChild(test);
test.value = mom.id + ' ' + mom.children.length;
}
birth(3, '#Marry');
birth(5, '#Liz');
birth(2, '#Betty');
div {
outline: 1px solid black;
width: 100px;
height: 30px;
}
output {
outline: 1px solid red;
color: red;
margin: 10px auto;
padding: 2px;
float: left;
}
.mom {
outline: 1px dashed blue;
width: 100px;
height: auto;
padding: 5px;
display: inline-block;
}
<div id="Marry" class="mom">Marry</div>
<div id="Liz" class="mom">Liz</div>
<div id="Betty" class="mom">Betty</div>
did you put this in window.onload event handler? your code is working, check this fiddle
window.onload=function(){
function birth(xkids, mom)
{
for( var i = 0; i < xkids; i++ )
{
mom.appendChild(document.createElement("div"));
mom.children[i].setAttribute("id", "child-"+i);
}
document.getElementById("test-output-1").innerHTML = mom.children.length; // now there are 3 children
}
var marry = document.getElementById("Marry"); // currently no child
birth(3, marry);
function whereIsTheChildren()
{
document.getElementById("test-output-2").innerHTML = marry.children.length; // there are 0 children
}
whereIsTheChildren();
}

Is there a way to get all event-listener bindings in Javascript?

I am searching for a way where I can list all event-listener bindings that are made with JS (or other scripts as well) on a website. Mainly I want to find out double bindings (for debug reason), but I guess there are other issues for it as well.
Brilliant would be a plugin for the browser, where you can see on the website which elements have which kinds of eventlisteners bound. You know, some visualization of the event-listeners...
Visual Event (http://www.sprymedia.co.uk/article/Visual+Event+2) is very helpful. Go to this page and just drag the "Visual Event" link into your bookmark bar. When you want to check a page, just click it, wait a second, and the events for each element will be overlaid on the page.
There's only one type of event declaration that you get it, I don't know if this will help you:
// Can't get
myDiv.attachEvent ("onclick", function () {alert (1)});
// Can't get
myDiv.addEventListener ("click", function () {alert (1)}, false);
// Can't get
<div onclick = "alert (1)"></div>
// Can get
myDiv.onclick = function () {alert (1)}
You may look this answer too. Anyway I made a function for you:
<!DOCTYPE html>
<html>
<head>
<script>
function getAllEvents () {
var all = document.getElementsByTagName ("*");
var _return = "";
for (var i = 0; i < all.length; i ++) {
for (var ii in all[i]) {
if (typeof all[i][ii] === "function" && /^on.+/.test (ii)) { // Unreliable
_return += all[i].nodeName + " -> " + ii + "\n";
}
}
}
return _return;
}
document.addEventListener ("DOMContentLoaded", function () {
var div = this.getElementsByTagName ("div")[0];
div.onclick = function () {
alert (1);
}
div.onmouseout = function () {
alert (2);
}
alert (getAllEvents ());
}, false);
</script>
<style>
div {
border: 1px solid black;
padding: 10px;
}
</style>
</head>
<body>
<div></div>
</body>
</html>
I just wrote a script that lets you achieve this. It gives you two global functions: hasEvent(Node elm, String event) and getEvents(Node elm) which you can utilize. Be aware that it modifies the EventTarget prototype method add/RemoveEventListener, and does not work for events added through HTML markup or javascript syntax of elm.on_event = ..., works only for add/RemoveEventListener.
More info at GitHub
Live Demo
Script:
var hasEvent,getEvents;!function(){function b(a,b,c){c?a.dataset.events+=","+b:a.dataset.events=a.dataset.events.replace(new RegExp(b),"")}function c(a,c){var d=EventTarget.prototype[a+"EventListener"];return function(a,e,f,g,h){this.dataset.events||(this.dataset.events="");var i=hasEvent(this,a);return c&&i||!c&&!i?(h&&h(),!1):(d.call(this,a,e,f),b(this,a,c),g&&g(),!0)}}hasEvent=function(a,b){var c=a.dataset.events;return c?new RegExp(b).test(c):!1},getEvents=function(a){return a.dataset.events.replace(/(^,+)|(,+$)/g,"").split(",").filter(function(a){return""!==a})},EventTarget.prototype.addEventListener=c("add",!0),EventTarget.prototype.removeEventListener=c("remove",!1)}();

Categories

Resources