Using Vue.js: How to Trigger a Child Method from the Parent Component

I recently explored the communication between components using vuejs and vuex. Here is a scenario I encountered:

  1. The first component is a menu
  2. The second component, nested within the first, is a hamburgerButton.

In this specific case, when I click the hamburgerButton, both the button and the menu animate. The code I have implemented ensures that after clicking the button, the menu transitions with vueTransition and so does the hamburgerButton. I am also utilizing vuex to manage the state of menuIsOpen.

However, the issue arises when I click an item in the menu. I want the animation of the hamburgerButton to be triggered as well.

The animation method for hamburgerButton, invoked by animButtonHandler(), is nested within a @click event. I understand why it is not functioning correctly at the moment, but I am unsure how to link this method to a click event on a parent element (an item in the menu). Therefore, my question is, how can I access a method in a child component from a parent component? Alternatively, is there another effective method to achieve this?

Parent component - menu.vue :

<template>
    <div class="menu">
        <!-- import hamburgerButton component -->
        <hamburger-button></hamburger-button>
        <transition v-on:enter="enterMenuHandler" v-on:leave="leaveMenuHandler">
            <div class="menu_wrapper" v-if="this.$store.state.menuIsOpen">
                <ul class="menu_items">
                    <li class="menu_item" @click="$store.commit('toggleMenu')">
                        <router-link class="menu_link" to="/">home</router-link>
                        <router-link class="menu_link" to="/contact">contact</router-link>
                    </li>
                </ul>
            </div>
        </transition>
    </div>
</template>

<script>
import hamburgerButton from "hamburgerButton.vue";

export default {
    components: {
        'hamburger-button': hamburgerButton,
    },
    methods: {
        enterMenuHandler(el, done){
            TweenLite.fromTo(el, 0.5, {
                opacity: '0',
            },{
                opacity: '1',
                onComplete: done
            });
        },
        leaveMenuHandler(el, done){
            TweenLite.to(el, 0.5, {
                opacity: '0',
                onComplete: done
            });
        },
    }
}
</script>

Child component: hamburgerButton.vue :

<template>
    <div class="hamburgerButton" @click="animButtonHandler()">
        <div class="hamburgerButton_inner" ref="hamburgerButtonInner">
            <i class="hamburgerButton_icon></i>
        </div>
    </div>
</template>

<script>
export default {
    methods: {
        animButtonHandler (){
            // toggle the state of the menu when button is clicked
            this.$store.commit('toggleMenu');
            const isOpen = this.$store.state.menuIsOpen === true;
            // animate the button
            TweenLite.to(this.$refs.hamburgerButtonInner, 0.5, {
                rotation: isOpen ? "43deg" : '0',
            });
        },
    }
}
</script>

store.js (imported in the main.js) :

let store = new Vuex.Store({
    state : {
            menuIsOpen : false,
    },
    mutations: {
        toggleMenu(state) {
            state.menuIsOpen = !state.menuIsOpen
         }
    }
});

Answer №1

Here is a simple example of how to use an event bus. Feel free to review it and make any necessary adjustments.

If you encounter any challenges, please leave a comment.

<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="691f1c0c295b4758475859">[email protected]</a>/dist/vue.min.js"></script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id="app">
<h2>event bus</h2>    
<button @click="callChildAnimateMethod"> Button On Parent Call Child </button>     
<childcmp><childcmp />
</div>
<script>  
var EventBus = new Vue();

Vue.component('childcmp', {
template: `<div>child demo - {{ message }}</div>`,
data: function() {
return {
message: 'hello'
}
},
mounted: function() {
// listen for event
EventBus.$on('animate', this.animButtonHandler);
},
destroyed: function(){
// remove listener
EventBus.$off('animate', this.animButtonHandler);

},
methods: {
animButtonHandler: function() {
console.log('this is child method');
this.message = 'I am changed.'
}
}
});

new Vue({
el: '#app',
data: function() {
return {

}
},
methods: {
callChildAnimateMethod: function() {          
EventBus.$emit('animate');
}
}

});
</script>
</body>
</html>

Update


Make sure to define EventBus

eventbus.js

import Vue from 'vue';
const EventBus = new Vue();
export default EventBus;

Parent component - menu.vue

import EventBus from './eventbus.js'
... your code

Child component: hamburgerButton.vue :

import EventBus from './eventbus.js'
... your code

Now, EventBus will be accessible to your code.

Answer №2

For those interested in integrating an event bus with their code, here is a simple guide:

Start by creating an event bus, which is essentially an empty Vue instance.

Include it in your main.js file or store it in a separate file.

main.js

export const EventBus = new Vue();

menu.vue

<template>
    <div class="menu">
        <!-- import hamburgerButton component -->
        <hamburger-button></hamburger-button>
        <transition v-on:enter="enterMenuHandler" v-on:leave="leaveMenuHandler">
            <div class="menu_wrapper" v-if="this.$store.state.menuIsOpen">
                <ul class="menu_items">
                    <li class="menu_item" @click="toggleMenu">
                        <router-link class="menu_link" to="/">home</router-link>
                        <router-link class="menu_link" to="/contact">contact</router-link>
                    </li>
                </ul>w
            </div>
        </transition>
    </div>
</template>

<script>
import hamburgerButton from "hamburgerButton.vue";
import {EventBus} from './path/to/main.js' //or a path to file where you exported your EventBus

export default {
    components: {
        'hamburger-button': hamburgerButton,
    },
    methods: {
        toggleMenu(){
            this.$store.commit('toggleMenu');
            EventBus.$emit('animate-hamburger-btn');
        },
        enterMenuHandler(el, done){
            TweenLite.fromTo(el, 0.5, {
                opacity: '0',
            },{
                opacity: '1',
                onComplete: done
            });
        },
        leaveMenuHandler(el, done){
            TweenLite.to(el, 0.5, {
                opacity: '0',
                onComplete: done
            });
        },
    }
}
</script> 

Add an event listener to the event bus in the created hook and trigger the animation on every animate-hamburger-btn event

hamburgerButton.vue

<template>
    <div class="hamburgerButton" @click="animButtonHandler()">
        <div class="hamburgerButton_inner" ref="hamburgerButtonInner">
            <i class="hamburgerButton_icon"></i>
        </div>
    </div>
</template>

<script>
import {EventBus} from './path/to/main.js' //or a path to file where you exported your EventBus
export default {
    created(){
        EventBus.$on('animate-hamburger-btn', () => {
            this.animateBtn();
        });
    },
    methods: {
        animButtonHandler (){
            // toggle the state of menu if button clicked
            this.$store.commit('toggleMenu');
            this.animateBtn();
        },
        animateBtn(){
            const isOpen = this.$store.state.menuIsOpen === true;
            // animate the button
            TweenLite.to(this.$refs.hamburgerButtonInner, 0.5, {
                rotation: isOpen ? "43deg" : '0',
            });
        }
    }
}
</script> 

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

swap out a method within a publicly available npm module

Currently, I am using an API wrapper package that utilizes the request module for making API requests. While this setup works well in most cases, I am facing a situation where I need to use this package in a node-webkit environment and replace the request ...

Tips on utilizing CSS modules in React without changing class names

After starting to use css modules in my react project, I quickly realized the struggle of changing classnames to fit the requirements of css modules. For example, if we have a component using regular css: import React from 'react' import ". ...

What is the method for condensing content using a Bootstrap toggle button (checkbox)?

Incorporating Bootstrap 5.1, I have a set of buttons that trigger the display or hide some content using the collapse plugin <div class="col m-2"> <button type="btn" class="btn btn-outline-primary m-1" d ...

Error 400: Invalid Request: Issue encountered when swapping code for Asana access token using Next.js

Encountered a 400 Bad Request error while trying to exchange the code for an access token at . I am unsure of the cause and would appreciate any assistance. Below is the code: const GetAsanaAccessToken = async (req, res) => { const body = { grant ...

Tips for effectively grouping a JavaScript object array with the help of Lodash

I have an array of objects in JavaScript that looks like this: [{ day : "August 30th", id: 1, message : "lorem ipsum1" },{ day : "August 30th", id: 2, message : "lorem ipsum2" },{ day : "August 31th", id: 3, message : " ...

Unable to set a JSON data as a value for a JavaScript variable

I am currently developing a YT mp3 downloader using the API provided by youtubeinmp3. I have been successful in obtaining the download link in JSON format. https://i.stack.imgur.com/3mxF2.png To assign the value of "link" from the JSON to a JavaScript va ...

Attempting to retrieve data from the Model in a JavaScript function post-page render using NodeJS and EJS

I'm new to NodeJS and I'm working on my first application. I am using Ejs to create the user interface and passing a model with data displayed in a table. I'm attempting to access this model's data in a JavaScript function to avoid ano ...

Using Ajax to poll a Celery task

I am working on a Celery task that updates a PostgreSQL database gradually. In my Django application, I want to fetch the latest data from the database and display it in a template in real-time as the task progresses. I am looking to implement this real-ti ...

Create a solution that is compatible with both web browsers and Node.js

I am developing a versatile library that can be utilized in both the browser and in node environment. The project involves three json config files, with the latter two extending the tsconfig.json. tsconfig.json (contains build files) tsconfig.browser.js ...

I am struggling to make php redirect work using onclick() function

My PHP button is not redirecting properly. Assuming the page destination is correct, is there anything else that could be causing this issue? echo "<button id=\"create\" onclick=\"location.href('/team/teams.php?op=create');&bso ...

Unveil the content of a string by applying Base64 decoding in AngularJS

After encrypting a token sent from JAVA code to Angular using Base64 encryption, the next step is decryption: String token = "1345BCHCNB"; Cipher ecipher = Cipher.getInstance("AES"); String mykey = "1234567891234567"; SecretKey key = new SecretKey ...

Retrieve information from a text

I retrieved this data as a string from a webpage using jQuery and need help parsing it. When I attempted to use jQuery.parseJSON, I encountered the error Uncaught SyntaxError: Unexpected token n. The specific values I am looking for are "surl" and "imgur ...

Utilize state objects and child components by accessing sub-values within the object

I have a Dropzone component where multiple uploads can happen simultaneously and I want to display the progress of each upload. Within my Dropzone component, there is a state array called uploads: const [uploads, setUploads] = useState([]) Each element i ...

Locate all elements by a segment of the identification attribute

Is it feasible to achieve the following: I possess a collection of divs, all having IDs that conclude with '_font', such as 'body_font', 'heading_font', 'tagline_font', and so on. Is there a method to retrieve thes ...

What is the best way to align these div elements within a table cell?

I am encountering an issue with the placement of elements. What I am striving for is something like this: https://i.stack.imgur.com/VSFXE.png where a div with several other divs inside is positioned at the top of the td, and another div is at the bottom o ...

Is there a way to automatically determine the text direction based on the language in the input text?

When posting in Google Plus (and other platforms), I noticed that when I type in Persian, which is a right-to-left language, the text direction changes automatically to rtl and text-alignment:right. However, when I switch to English, the direction switches ...

"Using Vue 3 to teleport content to a specific element and swap out existing

I've successfully implemented the use of Vue 3 teleport to display elements within a div. Although teleport adds items to the specified element, it doesn't replace existing elements in the div. Is there a way to configure teleport to replace th ...

Step-by-step guide on integrating a specific location into Google Maps using React.js

I'm in the process of revamping my website using Reactjs. I want to incorporate a specific Google location with reviews on the map, similar to how it appears on this example (My current website is built on Wordpress). As of now, all I've been ab ...

The lack of versioning in Laravel's webpack setup for splitting code and lazy loading routes with Vue

I've been diving into a Laravel + Vue SPA project and attempted to improve performance by implementing code splitting and defining lazy routes. However, I'm facing an issue where the lazy route files are not being versioned. Let me break down th ...

What is the best way to organize data subsets in Firebase?

I am currently working on saving data from multiple sections within my webapp. One section involves storing employee information, while the other deals with employer group information. However, when I save this data in Firebase, it all gets organized by ID ...