JokerMartini
JokerMartini

Reputation: 6147

How to remove event listener from Vue Component

I have a Vue2 component which contains an added eventListener i created on mounted. I was wondering how do i properly remove this listener when the component is destroyed?

<template>
    <div>
      ...
    </div>
  </template>
  
  <script>
  export default {
    mounted() {
        window.addEventListener('click', (evt) => {
          this.handleClickEvent(evt)
        })
    },
    destroyed() {
      //   window.removeEventListener('click', ????);
    },
    methods: {
      handleClickEvent(evt) {
        // do stuff with (evt) 
      },
    },
  }
  </script>
  

Upvotes: 2

Views: 18418

Answers (2)

cipak
cipak

Reputation: 1466

You have to keep a reference to the registered click handler, in order to be able to remove it later:

mounted() {
  this.clickHandler = () => { ... };
  window.addEventListener('click', this.clickHandler);
}

beforeDestroy() {
  window.removeEventListener('click', this.clickHandler);
}

However, you seem to already have this function defined in the component. It's named handleClickEvent. So there's no reason to create an arrow function wrapper around it. You can use it directly:

mounted() {
  window.addEventListener('click', this.handleClickEvent);
}

beforeDestroy() {
  window.removeEventListener('click', this.handleClickEvent);
}

Another neat feature available in vue2 (and, sadly, not in vue3) is to dynamically register a hook, which allows adding and removing the handler in mounted(), without the need of keeping a reference to it in the component:

mounted() {
  const handler = () => { ... }; // local variable
  window.addEventListener('click', handler);
  this.$once('hook:beforeDestroy',
    () => window.removeEventListener('click', handler)
  );
}

https://v2.vuejs.org/v2/guide/components-edge-cases.html#Programmatic-Event-Listeners

Upvotes: 4

Nikola Pavicevic
Nikola Pavicevic

Reputation: 23500

You can use this.$el for whole component and destroy event like you created it:

Vue.component('Child', {
  template: `
    <div class="child">
      click for event
    </div>
  `,
  mounted() {
    this.$el.addEventListener('click', (evt) => {
      this.handleClickEvent(evt)
    })
  },
  beforeDestroy() {
    console.log('distroyed')
    this.$el.removeEventListener('click', (evt) => {
      this.handleClickEvent(evt)
    })
  },
  methods: {
    handleClickEvent(evt) {
      console.log(evt.currentTarget)
      // do stuff with (evt) 
    },
  },
})


new Vue({
  el: "#demo",
  data() {
    return {
      show: true
    }
  },
  methods: {
    toggleShow() {
      this.show = !this.show
    }
  }
})
.child {
  height: 150px;
  width: 200px;
  background: goldenrod;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
  <div>
    <button @click="toggleShow">mount/unmount component</button>
    <Child v-if="show" />
  </div>
</div>

Upvotes: 2

Related Questions