Go Back   CodingForums.com > :: Client side development > JavaScript programming

Before you post, read our: Rules & Posting Guidelines

Reply
 
Thread Tools Rate Thread
Enjoy an ad free experience by logging in. Not a member yet? Register.
Old 02-11-2013, 11:21 PM   PM User | #1
elitis
Regular Coder

 
Join Date: Sep 2010
Posts: 319
Thanks: 9
Thanked 6 Times in 6 Posts
elitis is an unknown quantity at this point
How to addEventListener with argument?

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
elitis is offline   Reply With Quote
Old 02-11-2013, 11:38 PM   PM User | #2
rnd me
Senior Coder

 
rnd me's Avatar
 
Join Date: Jun 2007
Location: Urbana
Posts: 3,454
Thanks: 9
Thanked 466 Times in 450 Posts
rnd me is a jewel in the roughrnd me is a jewel in the roughrnd me is a jewel in the rough
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%
rnd me is offline   Reply With Quote
Old 02-12-2013, 12:01 AM   PM User | #3
jmrker
Senior Coder

 
jmrker's Avatar
 
Join Date: Aug 2006
Location: FL
Posts: 2,764
Thanks: 29
Thanked 453 Times in 447 Posts
jmrker will become famous soon enough
Question

Quote:
Originally Posted by rnd me View Post
...
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.
jmrker is online now   Reply With Quote
Old 02-12-2013, 12:35 AM   PM User | #4
Old Pedant
Supreme Master coder!

 
Old Pedant's Avatar
 
Join Date: Feb 2009
Posts: 23,185
Thanks: 59
Thanked 3,995 Times in 3,964 Posts
Old Pedant is a name known to allOld Pedant is a name known to allOld Pedant is a name known to allOld Pedant is a name known to allOld Pedant is a name known to allOld Pedant is a name known to all
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.
Old Pedant is offline   Reply With Quote
Users who have thanked Old Pedant for this post:
jmrker (02-12-2013)
Old 02-12-2013, 12:40 AM   PM User | #5
rnd me
Senior Coder

 
rnd me's Avatar
 
Join Date: Jun 2007
Location: Urbana
Posts: 3,454
Thanks: 9
Thanked 466 Times in 450 Posts
rnd me is a jewel in the roughrnd me is a jewel in the roughrnd me is a jewel in the rough
Quote:
Originally Posted by jmrker View Post
@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%

Last edited by rnd me; 02-12-2013 at 12:51 AM..
rnd me is offline   Reply With Quote
Old 02-12-2013, 12:53 AM   PM User | #6
rnd me
Senior Coder

 
rnd me's Avatar
 
Join Date: Jun 2007
Location: Urbana
Posts: 3,454
Thanks: 9
Thanked 466 Times in 450 Posts
rnd me is a jewel in the roughrnd me is a jewel in the roughrnd me is a jewel in the rough
Quote:
Originally Posted by Old Pedant View Post
I *think* what Elitis is talking about is something like this:

that doesn't use addEventListener, and this in that case is the same as evt.target...
__________________
my site (updated 5/13)
STATS (2013/5) HTML5:90.2% MOB:14% IE7:0.5% IE8:8.6% IE9:9.8% IE10:10%
rnd me is offline   Reply With Quote
Old 02-12-2013, 01:09 AM   PM User | #7
Old Pedant
Supreme Master coder!

 
Old Pedant's Avatar
 
Join Date: Feb 2009
Posts: 23,185
Thanks: 59
Thanked 3,995 Times in 3,964 Posts
Old Pedant is a name known to allOld Pedant is a name known to allOld Pedant is a name known to allOld Pedant is a name known to allOld Pedant is a name known to allOld Pedant is a name known to all
Quote:
Originally Posted by rnd me View Post
that doesn't use addEventListener
I know. I was sloppy.

But principal is same.

If you want to add an extra argument or two, use an anonymous function.
Code:
    elm.addEventListener(
        "click", 
        function(evt) { doSomethingElse( evt, "with another   argument" ); },
         false );
Same thing you did, except yours fancier.

Quote:
, 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..
Old Pedant is offline   Reply With Quote
Old 02-12-2013, 02:46 AM   PM User | #8
jmrker
Senior Coder

 
jmrker's Avatar
 
Join Date: Aug 2006
Location: FL
Posts: 2,764
Thanks: 29
Thanked 453 Times in 447 Posts
jmrker will become famous soon enough
Old Pedant:
Thank you for the interesting example.
Very useful to my understanding, expecially after I figured out that:
Code:
      btn3.onclick = fundtion( ) { doEvenMore( this, 3, "zamboni", new Date() ); }
probably should have been:
Code:
      btn3.onclick = function( ) { doEvenMore( this, 3, "zamboni", new Date() ); }
jmrker is online now   Reply With Quote
Old 02-12-2013, 02:54 AM   PM User | #9
Old Pedant
Supreme Master coder!

 
Old Pedant's Avatar
 
Join Date: Feb 2009
Posts: 23,185
Thanks: 59
Thanked 3,995 Times in 3,964 Posts
Old Pedant is a name known to allOld Pedant is a name known to allOld Pedant is a name known to allOld Pedant is a name known to allOld Pedant is a name known to allOld Pedant is a name known to all
Now way! We have to stick with funcamentals, so fundtion it is!

Hey, I touch type. Mostly I type what I touch.
__________________
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.
Old Pedant is offline   Reply With Quote
Old 02-12-2013, 03:26 AM   PM User | #10
jmrker
Senior Coder

 
jmrker's Avatar
 
Join Date: Aug 2006
Location: FL
Posts: 2,764
Thanks: 29
Thanked 453 Times in 447 Posts
jmrker will become famous soon enough
@"rnd me"

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!)
jmrker is online now   Reply With Quote
Old 02-12-2013, 04:45 AM   PM User | #11
rnd me
Senior Coder

 
rnd me's Avatar
 
Join Date: Jun 2007
Location: Urbana
Posts: 3,454
Thanks: 9
Thanked 466 Times in 450 Posts
rnd me is a jewel in the roughrnd me is a jewel in the roughrnd me is a jewel in the rough
Quote:
Originally Posted by jmrker View Post
@"rnd me"

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%

Last edited by rnd me; 02-12-2013 at 04:59 AM..
rnd me is offline   Reply With Quote
Users who have thanked rnd me for this post:
jmrker (02-12-2013)
Old 02-12-2013, 04:49 AM   PM User | #12
rnd me
Senior Coder

 
rnd me's Avatar
 
Join Date: Jun 2007
Location: Urbana
Posts: 3,454
Thanks: 9
Thanked 466 Times in 450 Posts
rnd me is a jewel in the roughrnd me is a jewel in the roughrnd me is a jewel in the rough
Quote:
Originally Posted by Old Pedant View Post

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%
rnd me is offline   Reply With Quote
Old 02-13-2013, 02:01 AM   PM User | #13
jmrker
Senior Coder

 
jmrker's Avatar
 
Join Date: Aug 2006
Location: FL
Posts: 2,764
Thanks: 29
Thanked 453 Times in 447 Posts
jmrker will become famous soon enough
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?

Code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title> Untitled </title>
<script type="text/javascript">

</script>

<style type="text/css">

</style>
</head>
<body>
<div id="links">
<a href="http://www.webdeveloper.com" onclick="return false"> Webdeveloper </a><br>
<a href="http://www.codingforums.com" onclick="return false"> Coding Forums </a><br>
<a href="http://www.dreamincode.net" onclick="return false"> Dream In Code </a><br>
</div>

<script type="text/javascript">
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 + " times of " + links.length + ' buttons' ); 
         },
         false 
     );//end addevent
  });//end map()
}//end bindHandlers()

window.onload = function() { bindHandlers(); }

</script>

</body>
</html>
jmrker is online now   Reply With Quote
Old 02-13-2013, 10:19 AM   PM User | #14
Airblader
Regular Coder

 
Join Date: Jan 2013
Location: Germany
Posts: 356
Thanks: 3
Thanked 43 Times in 43 Posts
Airblader can only hope to improve
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..
Airblader is offline   Reply With Quote
Old 02-13-2013, 02:54 PM   PM User | #15
jmrker
Senior Coder

 
jmrker's Avatar
 
Join Date: Aug 2006
Location: FL
Posts: 2,764
Thanks: 29
Thanked 453 Times in 447 Posts
jmrker will become famous soon enough
Yes, that helps.
Appreciate your time.
jmrker is online now   Reply With Quote
Reply

Bookmarks

Jump To Top of Thread


Thread Tools
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 04:49 AM.


Advertisement
Log in to turn off these ads.