[javascript] How to access to a child method from the parent in vue.js

I have two nested components, what is the proper way to access to the child methods from the parent ?

this.$children[0].myMethod() seems to do the trick but it is pretty ugly, isn't it, what can be better way:

<script>
import child from './my-child'

export default {
  components: {
   child
  },
  mounted () {
    this.$children[0].myMethod()
  }
}
</script>

This question is related to javascript vue.js

The answer is


To communicate a child component with another child component I've made a method in parent which calls a method in a child with:

this.$refs.childMethod()

And from the another child I've called the root method:

this.$root.theRootMethod()

It worked for me.


Ref and event bus both has issues when your control render is affected by v-if. So, I decided to go with a simpler method.

The idea is using an array as a queue to send methods that needs to be called to the child component. Once the component got mounted, it will process this queue. It watches the queue to execute new methods.

(Borrowing some code from Desmond Lua's answer)

Parent component code:

import ChildComponent from './components/ChildComponent'

new Vue({
  el: '#app',
  data: {
    item: {},
    childMethodsQueue: [],
  },
  template: `
  <div>
     <ChildComponent :item="item" :methods-queue="childMethodsQueue" />
     <button type="submit" @click.prevent="submit">Post</button>
  </div>
  `,
  methods: {
    submit() {
      this.childMethodsQueue.push({name: ChildComponent.methods.save.name, params: {}})
    }
  },
  components: { ChildComponent },
})

This is code for ChildComponent

<template>
 ...
</template>

<script>
export default {
  name: 'ChildComponent',
  props: {
    methodsQueue: { type: Array },
  },
  watch: {
    methodsQueue: function () {
      this.processMethodsQueue()
    },
  },
  mounted() {
    this.processMethodsQueue()
  },
  methods: {
    save() {
        console.log("Child saved...")
    },
    processMethodsQueue() {
      if (!this.methodsQueue) return
      let len = this.methodsQueue.length
      for (let i = 0; i < len; i++) {
        let method = this.methodsQueue.shift()
        this[method.name](method.params)
      }
    },
  },
}
</script>

And there is a lot of room for improvement like moving processMethodsQueue to a mixin...


Parent-Child communication in VueJS

Given a root Vue instance is accessible by all descendants via this.$root, a parent component can access child components via the this.$children array, and a child component can access it's parent via this.$parent, your first instinct might be to access these components directly.

The VueJS documentation warns against this specifically for two very good reasons:

  • It tightly couples the parent to the child (and vice versa)
  • You can't rely on the parent's state, given that it can be modified by a child component.

The solution is to use Vue's custom event interface

The event interface implemented by Vue allows you to communicate up and down the component tree. Leveraging the custom event interface gives you access to four methods:

  1. $on() - allows you to declare a listener on your Vue instance with which to listen to events
  2. $emit() - allows you to trigger events on the same instance (self)

Example using $on() and $emit():

_x000D_
_x000D_
const events = new Vue({}),_x000D_
    parentComponent = new Vue({_x000D_
      el: '#parent',_x000D_
      ready() {_x000D_
        events.$on('eventGreet', () => {_x000D_
          this.parentMsg = `I heard the greeting event from Child component ${++this.counter} times..`;_x000D_
        });_x000D_
      },_x000D_
      data: {_x000D_
        parentMsg: 'I am listening for an event..',_x000D_
        counter: 0_x000D_
      }_x000D_
    }),_x000D_
    childComponent = new Vue({_x000D_
      el: '#child',_x000D_
      methods: {_x000D_
      greet: function () {_x000D_
        events.$emit('eventGreet');_x000D_
        this.childMsg = `I am firing greeting event ${++this.counter} times..`;_x000D_
      }_x000D_
    },_x000D_
    data: {_x000D_
      childMsg: 'I am getting ready to fire an event.',_x000D_
      counter: 0_x000D_
    }_x000D_
  });
_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.28/vue.min.js"></script>_x000D_
_x000D_
<div id="parent">_x000D_
  <h2>Parent Component</h2>_x000D_
  <p>{{parentMsg}}</p>_x000D_
</div>_x000D_
_x000D_
<div id="child">_x000D_
  <h2>Child Component</h2>_x000D_
  <p>{{childMsg}}</p>_x000D_
  <button v-on:click="greet">Greet</button>_x000D_
</div>
_x000D_
_x000D_
_x000D_

Answer taken from the original post: Communicating between components in VueJS