Calling a method in a component outside that component is something we have to do sometimes. But how exactly can we do that? Are there multiple ways? What is the best practice?
In this article, I try to answer these questions, show you how i like to do it and give some code examples on how you can implement some of my favorite methods in your Vue app.
Alright let’s get started.
1. Using Event Bus
Using an event bus is one way to do it. The event bus can be used in most scenarios: sibling-to-sibling, cousin-to-cousin, parent-to-child, child-to-parent. When it comes to the event bus i would recommend that you use in the case of calling a method in a sibling-to-sibling or cousin-to-cousin scenario, why? Because i do believe that there is other more convenient ways for the other scenarios.
What is an event bus?
Essentially an event bus is a Vue.js instance that can emit events in one component, and then listen and react to the emitted event in another component.
There are two ways of implementing an event bus in your project:
1. Implementing the event bus as an instance property
An instance property explained in one sentence is a property (or variable) that you wanna make available global for all your components without polluting the global scope.
Okay, that all sounds really cool and all but how do I set it up in my app? Great question, it’s actually fairly simple once you got the hang of it.
import Vue from 'vue';
Vue.prototype.$eventBus = new Vue();
And you can then access it anywhere in your app like this:
this.$eventBus
Implementing the event bus as an ES6 module
The other way of implementing an event bus is as an ES6 module. Now it might sound scary at first but stay with me here, it is actually not that difficult and can be done in only a few lines of code.
First, we need to create the ES6 module. So let’s do that:
- Start by creating a new file in your project called event-bus.js.
- Then add the following code to the same file:
import Vue from 'vue';
const EventBus = new Vue();
export default EventBus;
As might have already noticed this is very similar to the instance property. We are creating a variable and then exporting the variable so that we can use it in our app.
Tada!! now we have created an ES6 module. See that wasn’t that bad.
Now, all we have to do is import it to the components that we want to use it in and we’ll import it like this:
<script>
import EventBus from './event-bus.js'
export default {
...
}
</script>
When we have implemented the event bus in our app we can then emit an event in one of our components like this:
<script>
export default {
methods: {
callMethodInChildComponent() {
//As an instance property
this.$eventBus.$emit("callMethodInChild");
//As an ES6 module.
EventBus.$emit("callMethodInChild");
},
},
};
</script>
And then in the other component we listen for the event and then executing the method like this:
<script>
export default {
mounted() {
//As an instance property
this.$eventBus.$on("callMethodInChild", () => {
this.methodInChild();
});
//As an ES6 module
EventBus.$on("callMethodInChild", () => {
this.methodInChild();
});
},
methods: {
methodInChild() {
//Execute code
},
},
};
</script>
2. Using $refs
Using the $refs property is a great and simple way of calling a components method from the parent component so to reference the before mentioned scenarios this would be the parent-to-child scenario.
What are $refs property and how do we use it?
The $refs property is used to reference DOM elements in the Vue instance’s templates.
To use the $refs property assign a reference ID to the child component you want to reference using the ref attribute. For example:
<template>
<child-component ref="childComponent"></child-component>
</template>
Now we can access the child components methods and then call the method directly from the parent component like this:
<script>
export default {
methods: {
callMethodInChildComponent() {
this.$refs.childComponent.methodInChild();
},
},
};
</script>
3. The good old $emit
The $emit property is the last way of calling a components method outside the component that I will show you in this article.
The scenario for using the $emit property would be when you want to call a method in a parent component from the child component also what I call the child-to-parent scenario.
What is the $emit property and how do we use it?
The $emit property is used for emitting a custom event from our child component and we can then listen for the same custom event in our parent component.
The $emit property unlike components and props, event names don’t provide any automatic case transformation. Instead, the name of an emitted event must exactly match the name used to listen to that event. For example, if emitting a camelCased event name like “updateItem”, listening to the kebab-cased version “update-item” will have no effect.
Emitting the event in the child component:
<script>
export default {
methods: {
callMethodInParentComponent() {
this.$emit("callMethodInParent");
},
},
};
</script>
Listening for the event in the parent component:
<template>
<child-component v-on:callMethodInParent="callMethodInParent">
</child-component>
</template>
Conclusion
So now that I have shown you some of my favorite ways of calling a components method outside of the component, You might still sit with one question. What is the best practice? And thats completely understandable because i didn’t really answer the question and here is why:
There isn’t one right way to do it since some of the methods mentioned above only work in specific scenarios and therefore the best practice depends so much more than just some guy in an article picking one for you. It depends on what relation does your component have to the component that you want to call the method from, and of course what do you prefer or what is already used in the project your working on.
I hope that you learned something new or maybe this article brought you closer to deciding on which method you want to use for calling a components method outside the component in your project.
If you have any questions put in the comments and i will do my very best to answer, this also applies if you have a fourth (or maybe even a fifth) way of calling a components method outside that component, put it down in the comments so that we can all learn from each other.
Top comments (2)
Thans for the article! I'd like to share how I implement component communication in my apps, since it's vanilla JS and thus framework agnostic it may give another point of view.
I currently use Vue for my apps, but before that I used plain JS and then jQuery and sometimes I needed a way to notify my components of some events. When learning the Windows API back on my days I learned about the event message system and thought that philosophy would work well for my JS needs.
The basic idea is use JavaScript's dispatchEvent to emit a CustomEvent message. Any other component in my app could listen to those message and take action.
So let's say we have a data table component that lists our app's sales, and we want to update the table in real time whenever a sale is completed. To achieve this our API should notify the web app of the sale using Pusher or any other web socket solution, and when we receive that notification we emit the message event. I've chosen WM_MESSAGE for the event name as a wink to the good old Windows API, where all messages begin with WM_.
In our data table component we would then listen to the WM_MESSAGE event and take action if the message id is NEW_SALE:
You can emit as many
WM_MESSAGE
events as you need with differentmsgId
properties to notify your app components of any local or remote event.What I like most about this method is that is just plain JS! When I switched from jQuery to Vue I had to rewrite my components but didn't have to change this code, since it didn't depend on any jQuery feature. And since it doesn't use any Vue features no change will be required when I upgrade to Vue 3 or change to another framework in the future.
Yes, exactly! Maybe I should have mentioned that this for vue 2