DEV Community

terrierscript
terrierscript

Posted on

TIL - Vue.js Event Bus more clearly

Vue.js event bus technique is sometime useful.

// ModalEvent.js
import Vue from "vue"

export const ModalEvent = new Vue()
<script>
import Vue from "vue"
import VModal from "vue-js-modal"
import { ModalEvent } from "./ModalEvent"

Vue.use(VModal)

export default {
  created(){
    ModalEvent.$on("openModal", () => {
      this.$modal.show("hello-modal")
    })
  }
}
</script>
<!-- event trigger component -->
<script>
import { ModalEvent } from "./ModalEvent"

export default {
  methods:{
    onClick(){
      ModalEvent.$emit("openModal")
    }
  }
}
</script>

But it have tiny problem that Event.$on and Event.$emit 's event signature is string, and it's can easily mistake.

Solution

I found it's can solve with use Event.methods.

// ModalEvent.js
import Vue from "vue"

const OPEN_MODAL = "openModal"
export const ModalEvent = new Vue({
  methods: {
    emitOpenModal(event){
      this.$emit(OPEN_MODAL, event)
    },
    onOpenModal(cb){
      this.$on(OPEN_MODAL, cb)
    }
  }
})
<script>
import Vue from "vue"
import VModal from "vue-js-modal"
import { ModalEvent } from "./ModalEvent"

Vue.use(VModal)

export default {
  created(){
    ModalEvent.onOpenModal( () => {
      this.$modal.show("hello-modal")
    })
  }
}
</script>
<script>
import { ModalEvent } from "./ModalEvent"

export default {
  methods:{
    onClick(){
      ModalEvent.emitOpenModal()
    }
  }
}
</script>

Top comments (4)

Collapse
 
rizkmeriouli profile image
Rizk MERIOULI

Hello, Terrierscript.
could you please guide me to test this modal vuejs component with JEST ?

import Vue from 'vue'
import { TeamMember } from '@/components/TeamMember.vue'
import { mount } from "@vue/test-utils"

describe('TeamMember.vue', ()=>{
it('renders a link', () => {
const wrapper = mount(TeamMember)
expect(wrapper.text(true)).toEqual(true)
})
})

Collapse
 
terrierscript profile image
terrierscript

Sorry for late ( I missed this comment.)

Hmm, this solution is un-test friendly ( I noticed this now )

If I need test this, I mocked ModalEvent.
use with jestjs.io/docs/en/manual-mocks#moc... or sinonjs.org/

Collapse
 
moe64 profile image
Moe

cool! I find Redux/Vuex really confusing, but this EventBus method looks like a simpler solution.

Collapse
 
dayvidwhy profile image
David Young

You can even use this technique while still making use of Vuex.

I like it the most when I want to avoid storing extra stuff in state, like having some vue instance commit a flag, that another vue instance is watching. That would be like a vue1 -> state -> vue2 pathway.

I can instead just use the EventBus as like a side passage, just emit from 1 vue component and listen to it in the other one so I'm instead going vue1 -> EventBus -> vue2.