When I was learning about the addEventListener method, I read that you're not supposed to include the parenthesis on the function you want to run because it will cause the event listener to 'fire off' immediately. If this is true, then how would you add an argument to a function you want to run?
__________________ Coding is a challenge, get used to it Always remember to debug Try the guess & check method Break it down into simple steps
event listeners don't pass arguments: the event object is generated by the browser and passed as the first and only argument.
if you want to reach other data, give the data a name and point your handler to that name.
if you are adding many handlers to many elms in a loop, it can be slightly complicated.
in that case, i would use Array.map instead of the for, and your variables will magically line up when the handler fires later because map() uses a function, and the function has its own scope, unlike a for-loop routine where all handlers inherit the same scope.
you can use jQuery's map() to accomplish the same thing in old-school browsers.
__________________ my site (updated 5/13) STATS (2013/5) HTML5:90.2% MOB:14% IE7:0.5% IE8:8.6% IE9:9.8% IE10:10%
...
if you want to reach other data, give the data a name and point your handler to that name.
if you are adding many handlers to many elms in a loop, it can be slightly complicated.
in that case, i would use Array.map instead of the for, and your variables will magically line up when the handler fires later because map() uses a function, and the function has its own scope, unlike a for-loop routine where all handlers inherit the same scope.
...
@rnd me:
Would you happen to have a brief example of the code that would accomplish this? Something simple with the extra parameter(s).
Preferably without using JQuery so I could understand the basics.
I *think* what Elitis is talking about is something like this:
Code:
<form id="theForm">
<input type="button" name="Button1" value="click here" />
<input type="button" name="Button2" value="or here" />
<input type="button" name="Button3" value="or finally here" />
</form>
<script type="text/javascript">
(
function( )
{
var form = document.getElementById("theForm");
var btn1 = form.Button1;
var btn2 = form.Button2;
var btn3 = form.Button3;
btn1.onclick = doSomething;
btn2.onclick = function(evt) { doSomethingElse( evt, "with another argument" ); }
btn3.onclick = fundtion( ) { doEvenMore( this, 3, "zamboni", new Date() ); }
function doSomething( evt )
{
if ( evt == null ) { evt = window.event; }
... now code to do something using the event ...
}
function doSomethingElse( evt, arg2 )
{
if ( evt == null ) { evt = window.event; }
... now code to do something using the event *AND* the other argument...
}
function doEvenMore( withButton, num, name, when )
{
... do something with the four arguments ...
... this time no event used ...
}
}
)();
</script>
Elitis: Assuming I understood you, then hopefully you now see the "trick": You create an anonymous function and use *IT* to pass the arguments that you need. You can see there how you can pass along the event or this reference, if you want them.
__________________
An optimist sees the glass as half full.
A pessimist sees the glass as half empty.
A realist drinks it no matter how much there is.
@rnd me:
Would you happen to have a brief example of the code that would accomplish this? Something simple with the extra parameter(s).
Preferably without using JQuery so I could understand the basics.
Code:
function bindHandlers(){
var links=$("a").toArray();
link.map(function mapper(elm, index){
elm.addEventListener(
"click",
function clicker(e){
alert( "You clicked the link pointing to " +
elm.href +"\nLink # "+
++index + " of " +
links.length );
},
false
);//end addevent
});//end map()
}//end bindHandlers()
here i closed links , grabbing the length property each event invocation (named clicker), and used [].map with an anon function named mapper as a loop construct.
this is good for "looped" setTimeout calls as well because the mapped function grabs "index" as a whole separate entity, unlike the typical for-loop "i" var which is always the loop length by the time the event actually fires...
also, you can avoid the .toArray() if you switch the arguments around (index, elm) on the map: jQuery's map() is backwards from ecma5's map(). it goes without saying that this fact makes me sad and angry.
but i needed a third party obje1ct for the demo, so i made a normal array to point to from the event handlers.
EDIT: changed to addEventListenter format instead of direct binding (doh!)...
EDIT2: oops, you said WITHOUT jQuery.
change
Code:
var links=$("a").toArray();
to
Code:
var links=[].slice.call(document.links);
to kill jq
__________________ my site (updated 5/13) STATS (2013/5) HTML5:90.2% MOB:14% IE7:0.5% IE8:8.6% IE9:9.8% IE10:10%
, and this in that case is the same as evt.target...
Well, unless of course you are in MSIE 8 or below where there's no evt.target. I tend to use this and avoid event unless another reason. I still have way way way too many customers using MSIE 7. And, as I discovered a couple of weeks ago, some still using MSIE 5 !!!
****
EDIT: Some actual numbers:
294 MSIE 5.5
3845 MSIE 6
4632 MSIE 7
9991 MSIE 8
15693 MSIE 9
1219 MSIE 10
20557 Chrome (all versions)
16911 Firefox
51728 WebKit (all versions)
12645 Macintosh (all browsers)
804 Opera
and so on...
I sure can't abandon MSIE pre version 9, however much I'd like to.
__________________
An optimist sees the glass as half full.
A pessimist sees the glass as half empty.
A realist drinks it no matter how much there is.
Last edited by Old Pedant; 02-12-2013 at 01:46 AM..
Thanks.
Your script of post #5 looks pretty slick, but you code above my pay grade
as I have been unable to get it to do anything yet...including the alert message
Thanks.
Your script of post #5 looks pretty slick, but you code above my pay grade
as I have been unable to get it to do anything yet...including the alert message
(I'll keep trying!)
stupid typos. that's what you get for renaming the array in the message reply box instead of firebug.
complete, jQuery less code below, tested on FF + Chrome
Code:
function bindHandlers(){
var links=[].slice.call(document.links);;
links.map(function mapper(elm, index){
elm.addEventListener(
"click",
function clicker(e){
alert( "You clicked the link pointing to " +
elm.href +"\nLink # "+
++index + " of " +
links.length );
},
false
);//end addevent
});//end map()
}//end bindHandlers()
bindHandlers()
the above code calls "elm" what the other calls "this" or "evt.target" or "evt.srcElement".
to me, that's less to type and is easier to read than "this", which can get confusing and means different things in attachEvent() as it does in addEventListener()...
PS: if your site's visitors are browser-challenged, don't forget the array methods inline compat pack.
i like http://danml.com/js/f.js, which gives you JSON, the Array methods and more for under 4kb.
pro tip: use an HTML conditional comment to add such external script only in IE8 and below...
__________________ my site (updated 5/13) STATS (2013/5) HTML5:90.2% MOB:14% IE7:0.5% IE8:8.6% IE9:9.8% IE10:10%
Well, unless of course you are in MSIE 8 or below where there's no evt.target. I tend to use this and avoid event unless another reason. I still have way way way too many customers using MSIE 7. And, as I discovered a couple of weeks ago, some still using MSIE 5 !!!
fair enough, for that you use a unified approach:
Code:
var targ=evt.target||evt.srcElement;
__________________ my site (updated 5/13) STATS (2013/5) HTML5:90.2% MOB:14% IE7:0.5% IE8:8.6% IE9:9.8% IE10:10%
I think I figured out how to use 'rnd me's code with the following example.
The only part I'm not sure of is how the variable 'index' works in this context.
It does seem to increment on each click of the link (essentially acts as a counter)
but I don't see where it is initialized nor where it is stored between clicks.
Can that be explained a bit more in my test code below?
Indeed, it is some tricky code. First, you get all links of the document and put it in an array. The code then calls the map function on it, which iterates over each element (= link) and applies a map function to it. This map function is passed the element and the index of the element within the array (this is where "index" comes from: it's initially 0 for the first link, 1 for the second link, …).
But instead of doing what you'd usually use the map function for, it just adds an event listener to each element. The index variable is within the closure of the mapper function and thus becomes a "counter" for each element (= link), with the little addition that the initial value is the index of the link within the document.
Is this sufficient to understand it?
Edit: To answer your two questions more specifically: the variable 'index' comes from the map function (see the documentation for Array.prototype.map) and it is 'stored' by keeping it alive in a closure. That's similar to this standard example:
Code:
var counter = (function () { var value = 0; return function () { alert(++value); }; })();
counter(); // 1
counter(); // 2
counter(); // 3
alert(value); // undefined
Last edited by Airblader; 02-13-2013 at 10:31 AM..