[Solved] Is it the right way to using global event bus?



  • I design the layout like this, there is a save button in the q-layout-header and different application in the child page. When I click save button, it will save different application. So I followed the documentation:
    1). in the child view, listen for an event

    export default {
    data (){ return …}
    created () {
    // listen for an event
    this.$root.$on(‘event_name’, saveXX())
    }
    methods: { }
    }
    function saveXX() { }
    

    2). in the main view, emitting an event when click save button

    this.$root.$emit(‘event_name’)
    

    There are two questions.
    1). Is it the best practice to trigger event? E.g., there are many buttons (save, print, download) in the toolbar in the main page, if child page want to support such function, how should they communicate.
    2). It seems saveXX can only be a function. If so, I can’t use data which is defined in the child vue component.



  • At question is really where to break down your application into different components, if at all. Once you decide that, you can communicate between components by having them raise events, which others listen out for and act on if necessary. Alternatively instead of notifying other components that something happened (and providing them with some optional information about that event), you might choose to store shared state globally, i.e. through Vuex.

    1. Best practice? No. The choice (depends on your circumstances and) remains yours as to whether you use events, callbacks between components, or shared state to communicate that something happened.
    2. You can pass data with the event, i.e. this.$root.$emit(‘event-name’, /some optional data/)


  • @Stanley I usually do mine in the mounted() function. I have had some issues in the created() function which I think were race conditions.
    Also, don’t forget to call this.$root.$off('event_name', saveXX()) in your beforeDestroy() function. (notice the $off).
    And, looks like you have the wrong type of single quotes.



  • @aryeh Thank you for your suggestion. I used Vuex to transfer state in different components, for current scenario, I know using Vuex could be a workaround, but it is a little complex because all different sub components have to handle the event when main component clicked the save button.
    Yes, it can pass data using method this.$root.$emit(‘event_name’, ‘some msg’). My current issue it that when triggering callback, the callback is a function and it can’t embedded in the sub vue component. It means it can’t access data defined in the sub component. (see fake code below the title)



  • @hawkeye64 Thanks for your suggestion.
    Did you try to access sub component’s data when execute callback function. It seems the callback function saveXX cannot be defined inside “export default”, do you have any idea?

    export default {
    data (){ return …}

    }
    function saveXX() { }



  • Make saveXX() a Vue instance method, rather than a global function as you’ve written, i.e. put it in “methods”. Alternatively, just execute your saveXX functionality in an anonymous function, e.g.

    created() {
      this.$root.$on('event_name', () => {
        // your saveXX functionality that can access current instances "data" through "this"
        // e.g. let myAge = this.age;
      }
    )
    


  • @aryeh Thank you very much! It works now.



  • @aryeh Could you please help me another problem? As Hawkeye64 suggested, don’t forget to call this.$root.$off(‘event_name’, saveXX()) in the beforeDestroy(), currently the callback is a anonymous function, so can I write simply as this?
    this.$root.$off(‘event_name’). // ignore callback function



  • If you have a “long running application”, then use a “named” function as a global event bus listener rather than an anonymous one. This allows you to remove the event listener as Hawkeye64 mentioned.

    You should not just use the event name as an argument for the $off method. Doing so will remove all event listeners for this event name. A specific listener is removed by providing both the event name, and a reference to the listener.

    See the documentation for $off() at https://vuejs.org/v2/api/#vm-off for an explanation.

    Be aware that a global event bus (i.e. via Quasar’s $root) is normally used between sibling components. Parent-child components do not need to do so, and do not require any explicit cleanup.



  • @Stanley if you do not turn the event off in the beforeDestroy() then that stale code will be run unexpectedly. Unless that’s what you want it to do. But when that component is mounted again, you’ll create another event instance and it’ll get run twice, and so on.



  • Thank you all! Appreciate for your help! I learnt a lot.