Reputation: 62366
A demo of what I'm expecting to work is here: https://jsfiddle.net/qe766xn0/4/
The child component is firing an event that the parent component is not picking up on. According to this documentation on the event relationship between a child and parent I would expect this to work. What am I overlooking that's causing the lack of logs in my console?
Vue.component('child-component', {
template: '<div>Child</div>',
mounted() {
this.$emit('test');
},
methods: {
onClick: function() {
this.$emit('child-click-on');
}
}
});
var vm = new Vue({
el: '#app',
created: function () {
this.$on('test', function () {
console.log('test-on');
});
this.$on('child-click', function () {
console.log('child-click-on');
});
}
});
Upvotes: 1
Views: 1483
Reputation: 62366
@Bert posted a great answer, however at the end of the day it still requires a lot of complexity. The solution I ended up finding is to fire all events in the root event namespace. You can do this by using this.$root.$off()
and this.$root.$on()
.
Upvotes: 0
Reputation: 82449
First, this code
<child-component @click="onClick()"></child-component>
means that the root Vue is listening for the child component to emit a click
event, and that doesn't appear to be your intention. It seems like you really want to attach a click handler to the root div of your component, which has to be done in the component.
Vue.component('child-component', {
template: `
<div @click="onClick()">
Child
</div>`,
methods: {
onClick: function() {
this.$emit('child-click-on');
}
}
});
At that point, your component will be properly emitting the child-click-on
event.
Second, you set up the listener like this:
this.$on('child-click', function () {
console.log('child-click-on');
});
Let's quickly move past the fact that it's listening to the wrong event (it should be listening to child-click-on
because that is what is emitted) to the fact that by saying this.$on
you are listening for the parent or root Vue to emit the event, and that never happens, because the event is emitted by the component. Therefore you need to listen to the event on the component. Idiomatically, this is done by adding the handler in the template:
<child-component @child-click-on="onChildClick"></child-component>
There the root Vue is listening for the child-click-on
event, at which point it will call the onChildClick
method (which is just a method I defined for handing the event).
If, however, you were forced for some reason to set up the handler using $on
, you would need to use a ref to get a reference to the child component so that you could set up the event listener.
<child-component ref="child"></child-component>
And since refs are not available until the component is rendered, you would have to add the listener in the mounted
event.
mounted: function () {
this.$refs.child.$on('child-click-on', function () {
console.log('child-click-on');
});
}
So, here is an example of the problem solved idiomatically.
console.clear()
Vue.component('child-component', {
template: `<div @click="onClick()">
Child
</div>`,
methods: {
onClick: function() {
this.$emit('child-click-on');
}
}
});
var vm = new Vue({
el: '#app',
methods: {
onChildClick() {
console.log("child-click-on")
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<child-component @child-click-on="onChildClick"></child-component>
</div>
And here it is solved using a ref.
Vue.component('child-component', {
template: `
<div @click="onClick()">
Child
</div>`,
methods: {
onClick: function() {
this.$emit('child-click-on');
}
}
});
var vm = new Vue({
el: '#app',
mounted: function () {
this.$refs.child.$on('child-click-on', function () {
console.log('child-click-on');
});
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<child-component ref="child"></child-component>
</div>
Upvotes: 2