Home > Net >  Remove Event Listeners that need to Receive Multiple Arguments JS
Remove Event Listeners that need to Receive Multiple Arguments JS

Time:11-08

I built a tab that a user can close using touch events and when the tab closes I want to be able to remove event listeners. This is a little bit tricky because in my actual code there is a modal and there is a part in that dynamically inserted content that the touch events are attached to.

So if i have the below code

const tab = document.querySelector('.tab')

function handleMove(e, tab) {
  e.preventDefault()
  tab.style....
}

// I add the event listener like this
// but then I can't remove it
tab.addEventListener('touchmove', e => {
  handleMove(e, tab)
})

Below is more realistic with what I am dealing with.

const swipeTab = document.querySelector('.swipeable-tab')

let y1, timeStart, timeEnd

function closeStart(e) {
  e.preventDefault()
  let touchLocation = e.targetTouches[0]
  y1 = touchLocation.clientY
  console.log({ y1 })
  timeStart = e.timeStamp
}


function closeMove(e, swipeTab) {
  e.preventDefault()
  swipeTab.style.transform = ''
  let touchLocation = e.touches[0]
  let yLocation = touchLocation.clientY

  if (yLocation > swipeTab.clientHeight   y1) {
    yLocation = swipeTab.clientHeight   y1
  }

  swipeTab.style.transition = ''
  let marker = yLocation - y1
  console.log({ marker })

  if (marker < 0) {
    marker = 0
  }
  
  swipeTab.style.transform = `translate3d(0, ${marker}px, 0)`
}



function closeEnd(e, swipeTab) {
  e.preventDefault()
  let touchLocation = e.changedTouches[0]; 
  let y2 = touchLocation.clientY; 
  let yDiff = y2 - y1; 
  console.log({ yDiff })
  timeEnd = e.timeStamp; 
  timeDiff = timeEnd - timeStart; 
  console.log({ y2 })
  console.log({ timeDiff })

  if (yDiff > swipeTab.clientHeight/3 || timeDiff < 50) {
    closeTab(swipeTab)
  } else {
    openTab(swipeTab)
  }

}


function openTab(swipeTab) {
  swipeTab.style.transition = `all 0.2s ease-in-out`
  swipeTab.style.transform = `translate3d(0, 0%, 0)`
  addCloseEventListeners(swipeTab)
}

/**
 * I am trying to come up with something similar to this
*/

function closeTab(swipeTab) {
  swipeTab.style.transition = `all 0.2s ease-in-out`
  swipeTab.style.transform = `translate3d(0, 100%, 0)`
  removeCloseEventListeners(tab)
}

function removeCloseEventListeners(swipeTab) {
  swipeTab.removeEventListener('touchstart', closeStart); 
  swipeTab.removeEventListener('touchmove', closeMove); 
  swipeTab.removeEventListener('touchend', closeEnd); 
}


/**
 * when open(swipeTab) is called
 * then the event listeners are added for closing the tab
*/
function addCloseEventListeners(swipeTab) {

  swipeTab.addEventListener('touchstart', e => {
    closeStart(e)
  }) 

  swipeTab.addEventListener('touchmove', e => {
    closeMove(e, swipeTab)
  })

  swipeTab.addEventListener('touchend', e => {
    closeEnd(e, swipeTab)
  })
 }


/**
 * this is where it starts
*/
open(swipeTab)

CodePudding user response:

Make more variables.

function removeCloseEventListeners(swipeTab) {
  swipeTab.removeEventListener("touchstart", swipeTouchStart);
  swipeTab.removeEventListener("touchmove", swipeTouchMove);
  swipeTab.removeEventListener("touchend", swipeTouchEnd);
}

const swipeTouchStart = (e) => closeStart(e);
const swipeTouchMove = (e) => closeMove(e, swipeTab);
const swipeTouchEnd = (e) => closeEnd(e, swipeTab);

function addCloseEventListeners(swipeTab) {
  swipeTab.addEventListener("touchstart", swipeTouchStart);
  swipeTab.addEventListener("touchmove", swipeTouchMove);
  swipeTab.addEventListener("touchend", swipeTouchEnd);
}

Also, you don't need to make your functions take swipeTab as a parameter:

function addCloseEventListeners() {

since swipeTab is already a global variable in the script.

CodePudding user response:

I would probably create a helper function that adds a listener and returns a callback holding a removeEventListener() with the same signature that it was added with. You can then store these callbacks to be used in the removeCloseEventListeners() function, here using a global array and setting it's length to 0 after use.

This will redeclare the callbacks for each event with the passed swipeTab as argument and as the element the events will be attached to. It also avoids the repetition in your current code allowing you to define the events once in addCloseEventListeners() without having to also add/edit them in the close function.

function addEventListenerWithAnonymousCallback(element, event, cb, options = {}) {
  element.addEventListener(event, cb, options);
  
  return () => element.removeEventListener(event, cb, options);
}

const closeListeners = [];
function removeCloseEventListeners() {
  for (const removeListener of closeListeners) {
    removeListener();
  }
  closeListeners.length = 0;
}

function addCloseEventListeners(swipeTab) {
  const listeners = [
    ["touchstart", (e) => closeStart(e)]
    ["touchmove", (e) => closeMove(e, swipeTab)],
    ["touchend", (e) => closeEnd(e, swipeTab)],
  ];

  for (const [event, cb] of listeners) {
    const removeListener = addEventListenerWithAnonymousCallback(swipeTab, event, cb);
    closeListeners.push(removeListener);
  }
}
  • Related