Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add Vue lifecycle listener dynamically

I have certain functions that I need to be able to call when a vue component is destroyed, but I don't necessarily know what they are before the event is created.

Is there a way to dynamically add a listener to the vue lifecycle events?

What I'm trying to achieve:

...methods: {
    logOnDestroy(txt) {
        this.$on('beforeDestroy', () => {
            console.log(txt)
        }
    }
}

But that is not currently being called. Is there a different way to programatically bind listeners to component lifecycle events at runtime?

like image 464
Rafael Kennedy Avatar asked Feb 22 '18 16:02

Rafael Kennedy


2 Answers

You might ask, can it be simpler?

From Vue.js Component Hooks as Events, this is the syntax you are looking for

this.$once('hook:beforeDestroy', () => {

I'm not sure how exactly you intend to make it dynamic, but here is an adaption of your logOnDestroy() method in Vue CLI's default HelloWorld app,

Demo

Vue.component('helloworld', {
  template: '<h1>{{ msg }}</h1>',
  name: 'helloworld',
  props: { msg: String },
  mounted() {
    this.logOnDestroy('Goodbye HelloWorld')
  },
  methods: {
    logOnDestroy(txt) {
      this.$once('hook:beforeDestroy', () => {
        console.log(txt)
      })
    }    
  }
});

new Vue({
  el: '#app',
  data: {
    showHello: true
  },
  mounted() {
    setTimeout(() => {
      this.showHello = false
    }, 3000)
  }
});
Vue.config.productionTip = false
Vue.config.devtools = false
<script src="https://unpkg.com/vue"></script>
<div id="app">
  <img alt="Vue logo" src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/95/Vue.js_Logo_2.svg/277px-Vue.js_Logo_2.svg.png" style="height: 50px;">
  <helloworld v-if="showHello" msg="Welcome to Your Vue.js App"/>
</div>
like image 56
Ackroydd Avatar answered Sep 20 '22 04:09

Ackroydd


An array of handlers for each life-cycle event is stored in the this.$options object. You can add a handler by pushing to the corresponding array (you'll need to create the array first if there are no handlers set already):

new Vue({
  el: '#app',
  created() {
    if (!this.$options.mounted) {
      this.$options.mounted = [];
    }
  
    this.$options.mounted.push(() => {
      console.log('mounted')
    });
    
    this.$options.mounted.push(() => {
      console.log('also mounted')
    });
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.min.js"></script>

<div id="app">
  <div></div>
</div>

So in your case:

methods: {
  logOnDestroy(txt) {
    if (!this.$options.beforeDestroy) {
      this.$options.beforeDestroy = [];
    }

    this.$options.beforeDestroy.push(() => {
      console.log(txt)
    });
  }
}
like image 24
thanksd Avatar answered Sep 20 '22 04:09

thanksd