DEV Community

Cover image for Vue.js - How I call a method in a component from outside the component in Vue 2
jannick holm
jannick holm

Posted on • Updated on

Vue.js - How I call a method in a component from outside the component in Vue 2

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();
Enter fullscreen mode Exit fullscreen mode

And you can then access it anywhere in your app like this:

this.$eventBus
Enter fullscreen mode Exit fullscreen mode

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:

  1. Start by creating a new file in your project called event-bus.js.
  2. Then add the following code to the same file:
import Vue from 'vue';
const EventBus = new Vue();

export default EventBus;
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>

Enter fullscreen mode Exit fullscreen mode

Listening for the event in the parent component:

<template>
  <child-component v-on:callMethodInParent="callMethodInParent">
  </child-component>
</template>
Enter fullscreen mode Exit fullscreen mode

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.

Discussion (3)

Collapse
web2033 profile image
Eugene Kopich

Note that this is more related to Vue 2. In Vue 3 $on, $off and $once instance methods are removed. Component instances no longer implement the event emitter interface.

Collapse
jannickholmdk profile image
jannick holm Author

Yes, exactly! Maybe I should have mentioned that this for vue 2

Collapse
koas profile image
Koas

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_.

// A sale has been made, emit the message. orderId and amount are provided by the API.
const detail = {msgId: "NEW_SALE", orderId, amount};
const evt = new CustomEvent("WM_MESSAGE", {detail});
Enter fullscreen mode Exit fullscreen mode

In our data table component we would then listen to the WM_MESSAGE event and take action if the message id is NEW_SALE:

window.addEventListener("WM_MESSAGE", messageHandler);

function messageHandler(e)
{
  if (e.detail.msgId == "NEW_SALE")
  {
    // Here we would call our component's update data method
  }
}
Enter fullscreen mode Exit fullscreen mode

You can emit as many WM_MESSAGE events as you need with different msgId 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.