5
votes

I have a method initialized within the parent component called setMessage() and I'd like to be able to call it within the child component.

main.js

const messageBoard = new Vue({
    el: '#message-board',
    render: h => h(App),
})

App (App.vue (parent))..

export default {
    data() {
        return { messages: state }
    },
    methods: {
        setMessage(message) {
            console.log(message);
        }
    },
    template: `
        <div>
            <child-component></child-component>
        </div>
    `,
}

child

const child = Vue.extend({
    mounted() {
        // attempting to use this function from the parent
        this.$dispatch('setMessage', 'HEY THIS IS MY MESSAGE!');
    }
});
Vue.component('child-component', child);

Right now I'm getting this.$dispatch is not a function error message. What am I doing wrong? How can I make use of parent functions in various child components? I've also tried $emit, it doesn't throw an error & it doesn't hit the function.

Thank you for your help in advance!

2
Which version of Vue are you using?Peter
@Peter 2.1.10Modelesq

2 Answers

16
votes

You have a couple options.

Option 1 - referencing $parent from child

The simplest is to use this.$parent from your child component. Something like this:

const Child = Vue.extend({
  mounted() {
    this.$parent.setMessage("child component mounted");
  }
})

Option 2 - emitting an event and handling in parent

But that strongly couples the child to its parent. To fix this, you could $emit an event in the child and have the parent handle it. Like this:

const ChildComponent = Vue.extend({
  mounted() {
    this.$emit("message", "child component mounted (emitted)");
  }
})

// in the parent component template
<child-component @message="setMessage"></child-component>

Option 3 - central event bus

One last option, if your components don't have a direct parent-child relationship, is to use a separate Vue instance as a central event bus as described in the Guide. It would look something like this:

const bus = new Vue({});

const ChildComponent = Vue.extend({
  mounted() {
    bus.$emit("message-bus", "child component mounted (on the bus)");
  }
})

const app = new Vue({
  ...
  methods: {
    setMessage(message) {
      console.log(message);
    }
  }, 
  created() {
    bus.$on('message-bus', this.setMessage)
  },
  destroyed() {
    bus.$off('message-bus', this.setMessage)
  }
});

Update (Option 2a) - passing setMessage as a prop

To follow up on your comment, here's how it might work to pass setMessage to the child component as a prop:

const ChildComponent = Vue.extend({
  props: ["messageHandler"],
  mounted() {
    this.messageHandler('from message handler'); 
  }
})

// parent template (note the naming of the prop)
<child-component :message-handler="setMessage"></child-component>
0
votes
 // parent component providing 'foo'
        var Provider = {
            methods: {
                foo() {
                    console.log('foo')
                },
            },
            provide: {
                foo: this.foo,
            },
        }

        // child component injecting 'foo'
        var Child = {
            inject: ['foo'],
            created() {
                this.foo() // => "foo"
            },
        }