javascriptaddeventlistenerremoveeventlistener

Js: remove or disable previous added event listeners of a certain event


codepen

Take following example (same as codepen)

const div = document.querySelector('div');

function a(){
  console.log('a');
}

function b(){
  console.log('b');
}

div.addEventListener('click', e=>{
  a();
});

div.addEventListener('click', e=>{
  // I don't want all previous added event handlers to work, is there a way to remove it?
  b();
});
div{
  width: 200px;
  height: 200px;
  background: red;
}
<div></div>

the expected output is b;

In my original code, I have more than one event handlers, such as click, mousemove, etc. is there a way I can remove all event listeners of a particular event that I previously added?

For example, at the start, click to my button triggers function A; in the middle, I consider needing a functional change, so instead of triggering function A, I want function B, and only function B.

I have read:

but it didn't help much. thanks for your help.


update

To be more specific, is there a way to prevent previously added event listeners of click inside the new added function, for instance:


my_button.addEventListener('click', ()=>{
    console.log('a');
});

my_button.addEventListener('click', ()=>{
    // remove all previously added click handlers 
    console.log('b');
});


solution

Thanks to @Kayac, worked this out:

// add a new method to element, oneEventListener, 
// for a speficified event type, only save and execute last add handler

function elemental(el){
    el.oneEventListener = (event, func) => {
        if(el.lastEventListener == null){
          el.lastEventListener = {};
        }
        if(el.lastEventListener[event] != null){
          el.removeEventListener(event, el.lastEventListener[event]);
        }
        el.addEventListener(event, func);
        el.lastEventListener[event] = func;
    }
    return el;
}

// eventhandler singleton, support querySelector, getElementById, etc, even support querySelectorAll and getElementsByClassName
function proxy(el) {
  if(!(el instanceof NodeList)){
    return elemental(el);
  }else{
    el.forEach(ele=>{
      ele = elemental(ele);
    });
    return el;
  }
}

const div = proxy(document.querySelector('div'));
// const div = document.querySelector('div');

div.oneEventListener('click', e=>{
    console.log('a');
})

div.oneEventListener('click', e=>{
    console.log('b');
})

div.oneEventListener('click', ()=>{
    console.log('c');
})

div.oneEventListener('mouseover', ()=>{
    console.log('aa');
})

div.oneEventListener('mouseover', ()=>{
    console.log('bb');
})

div.oneEventListener('mouseover', ()=>{
    console.log('cc');
})
div{
  width: 200px;
  height: 200px;
  background: red;
}
<div></div>

Update

For visitors, if you are looking for html selector to allow you to perform singleton on event listener, following code is tuned for performance.

/* html element selector */

// element: one event maps to one handler
function elemental(el){
  el.oneEventListener = (event, func) => {
    if(el.lastEventListener == null){
      el.lastEventListener = {};
    }
    if(el.lastEventListener[event] != null){
      el.removeEventListener(event, el.lastEventListener[event]);
    }
    el.addEventListener(event, func);
    el.lastEventListener[event] = func;
  }
  return el;
}

// querySelector -> element
function proxy(el){
  return elemental(el);
}

// querySelectorAll -> NodeList
function proxyAll(el){
  el.forEach(ele=>{
    ele = elemental(ele);
  });
  return el;
}

/*
once proxy is implemented, by oneEventListener, 
only one event listener of particular type will exist on that element,
if you call addEventListener, proxy doesn't interfer it.
which the eventlistener added will work normally.
*/

// proxy query selector
const pqs = function(str){
  return proxy(document.querySelector(str));
}

// proxy query selector all
const pqsa = function(str){
  return proxyAll(document.querySelectorAll(str));
}

Solution

  • Try this

    function a() {
      console.log("a");
    }
    
    function b() {
      console.log("b");
    }
    
    function proxy(el) {
      const map = {};
    
      return {
        addEventListener: (event, func) => {
          !map[event] && el.addEventListener(event, () => map[event]());
    
          map[event] = func;
        }
      };
    }
    
    const div = proxy(document.querySelector("div"));
    
    div.addEventListener("click", a);
    div.addEventListener("click", b);