0

I'm trying to figure out how to get a child component to communicate with the parent component, without having a hard binding between them.

From what I've read, custom events should be the thing. But I can't get the parent component to receive and act on the event.

In my sample below I expect clicking on the "Do stuff" button in <child> to trigger doStuff() in <parent>. I see the log message that indicates the button was clicked, but I see no log message indicating that the emitted message was ever received by the parent.

Sample HTML:

<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  </head>

  <body>
    <div id="app">
      <parent>
        <child></child>
      </parent>
    </div>
  </body>
</html>

Sample Javascript:

Vue.component('parent', {
    props: [],
    template: `
        <div v-on:stuff="doStuff">
            <h1>Hello World (from parent)!</h1>
            <slot></slot>
        </div>
    `,
    methods: {
      doStuff: function() {
        console.log('Do stuff');
      }
    }
});

Vue.component('child', {
    props: [],
    template: `
        <div>
            Hello World (from child)!<br>
            <button v-on:click="performClick">Do stuff</button>
        </div>
    `,
    methods: {
      performClick: function() {
        console.log('Do something');
        this.$emit('stuff');
      }
    }
});

var app = new Vue({
  el: '#app',
})
1
  • The problem is you emitted on div, not any component.
    – tohasanali
    Commented Jan 30, 2020 at 8:26

1 Answer 1

1

You access to emitted is wrong . stuff is emitted from child component so you need to access that emit in child component tag so you should use child component tag in parent component template . Like below

Vue.component('parent', {
    props: [],
    template: `
        <div>
            <h1>Hello World (from parent)!</h1>
            <slot :test="doStuff"></slot>
        </div>
    `,
    methods: {
      doStuff: function() {
        console.log('Do stuff');
      }
    }
});

Vue.component('child', {
    props: [],
    template: `
        <div>
            Hello World (from child)!<br>
            <button v-on:click="performClick">Do stuff</button>
        </div>
    `,
    methods: {
      performClick: function() {
        console.log('Do something');
        this.$emit('stuff');
      }
    }
});

var app = new Vue({
  el: '#app'
})
<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  </head>

  <body>
    <div id="app">
      <parent>
        <template slot-scope="scope"><child v-on:stuff="scope.test"></child></template>
      </parent>
    </div>
  </body>
</html>

Updated

You need to use slot and set slot-scope in parent component by setting like :{scopeName} and then you can access from template by slot-scope . When child component is emitted , you just need to call that {scopeName}

1
  • Thank you for that clarification. The issue is that the <parent> component in my intended case can be a wrapper for any type of content, so I cannot "hard code" the child component. The end result will be that the parent component is a popup bubble with variable content. The child could be text, a form, an options menu etc. I want the child component to be able to send it a close message after some action performed by the child.
    – Chris
    Commented Jan 30, 2020 at 8:53

Not the answer you're looking for? Browse other questions tagged or ask your own question.