0

How to remove duplicate from addEventListener.

I have site which uses ajax to populate different divs when user makes certain calls. I also have a Javascript function which grabs all the links and make an addEventListener so that I can filter the url and if the user clicked on certain links give an alert. Below is my Javascript function which creates the addEventListener:

function supportFunction() {
   var myFunction = function(e) { 
     var regExp = new RegExp('//'+location.hostname+'($|/)');
     var href = this.href; 

     if (regExp.test(href)) {
       e.preventDefault();
       alert('same domain link');
     } 
   }
   var links = document.querySelectorAll('a');

   for (var i = 0; i < links.length; i++) {
     links[i].addEventListener('click', myFunction);
   }
}

The problem I am facing is, as some of the content gets populated using ajax after the supportfunction() is called, if any links are there in the newly populated content it wont be added to the addEventListener. I tried calling the supportfunction whenever an ajax call is made but in that case duplicates are added to eventlistener. That is, if someone clicks on the same domain link they will get 2 alerts, and some case 3-4 alert depending upon how many time the supportfunction() is called.

I guess I explained, what my problem is. Let me know if you want more explanation about the problem.

I tried googleing for an answer and found this link http://dean.edwards.name/weblog/2005/10/add-event/ but couldn't figure out how to use it in my case.

Note : I am looking for a pure Javascript solution not a jQuery solution. (I hope I am not demanding here :) )

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
user1846348
  • 241
  • 1
  • 10
  • 22
  • Look for "event delegation". Don't add the event on the links but on a static parent container, then use the event target element to figure out if it's a link. – elclanrs Feb 13 '14 at 01:08
  • I would attach *one* `click` event to the body and then check for `event.target` or `event.srcElement`. If the element is a link (`a`) then execute function. – JCOC611 Feb 13 '14 at 01:09
  • possible duplicate of [Event binding on dynamically created elements?](http://stackoverflow.com/questions/203198/event-binding-on-dynamically-created-elements) – Bergi Feb 13 '14 at 01:13
  • If you don't want to restructure your whole code to use event delegation, simple call `removeEventListener` with your old `myFunction` on every of the links right before you call `supportFunction` from the ajax callback. – Bergi Feb 13 '14 at 01:14
  • I tried attaching it to the body but it didt work. I do have 'event.stopPropagation ? event.stopPropagation() : (event.cancelBubble=true)' on the outer divs. – user1846348 Feb 13 '14 at 01:17
  • I am looking into event delegation , how to use it... its my first time hearing about it. – user1846348 Feb 13 '14 at 01:20
  • Horrible stuff when you click on a url and get an alert instead – Aran Mulholland Feb 13 '14 at 01:21
  • The alert is just for the example , I got functions to call if it is from the same domain. – user1846348 Feb 13 '14 at 01:22

2 Answers2

1

If you are only adding one listener and there are no others, you can do:;

links[i].onclick = myFunction;

and run the function every time you add elements. That way if there is a listener already on the link, it will be replaced by myFunction. Or you could do:

if (!links[i].onclick) {
  links[i].onclick = myFunction;
}

but delegation is likely the best solution: put a click listener on a parent of all the subject links (maybe a div) and test the event target (W3C DOM model) or srcElement (IE model) to see if it came from a link you care about.

Related MDN article: event.target.

RobG
  • 142,382
  • 31
  • 172
  • 209
1

You expect that every link be event-binded to only once. You can make a flag to mark if it has been event-binded. so the code is as below.

function supportFunction() {
   var myFunction = function(e) { 
       var regExp = new RegExp('//'+location.hostname+'($|/)');
       var href = this.href; 
       if (regExp.test(href)) {
           e.preventDefault(); 
           alert('same domain link'); } 
   }
   var links = document.querySelectorAll('a');
   for (var i = 0, len = links.length; i < len; i++) {
       var link = links[i];
       // make sure add-event only once
       if(!link.getAttribute('data-added')) {
           link.setAttribute('data-added', 1);
           link.addEventListener('click', myFunction); 
       }
   }
}
jansesun
  • 108
  • 5
  • There is a [*document.links*](http://www.w3.org/html/wg/drafts/html/CR/dom.html#dom-document-links) collection that should be faster and more convenient than *querySelectorAll*. – RobG Feb 13 '14 at 02:18