5

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? Commented Feb 24, 2017 at 19:55
  • @Peter 2.1.10 Commented Feb 24, 2017 at 19:57

2 Answers 2

17

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>
Sign up to request clarification or add additional context in comments.

7 Comments

Hmm. This works. But it worries me that should I have child components becoming parents and reusing the same functions. Would it end up looking something like this.$parent.$parent.setMessage()? And therefore becoming hard to keep track of.
I like the 2nd option better. Is it any different than bringing in setMessage as a prop? This also doesn't seem to work; not does it throw any helpful errors.
I hadn't thought about passing the function as a prop but that would be yet another option. Just added a code sample for this ... note the hyphenated name of the prop and the fact that it is bound.
I guess I would still have to include that props within the child child elements as well. I just don't know why $dispatch doesn't work. Anyway, thank you for your help!
Happy to help! Here's the part in the migration guide where they explain why they got rid of $dispatch in Vue 2 and what to do instead: vuejs.org/v2/guide/…
|
0
// 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";
  },
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.