Reputation: 4282
I'm wondering how to deal with dynamic components
and events
using vue-js 2.3
.
Let's say the component home
$emit('eventFromHome')
and the component archives
$emit('eventFromArchives')
What is the way to catch them in the <component></component>
? Does it exist a better/nicer way to do it than the temporary solution?
var vm = new Vue({
el: '#example',
data: {
currentView: 'home'
},
components: {
home: { /* ... */ },
posts: { /* ... */ },
archive: { /* ... */ }
}
})
<component v-bind:is="currentView"></component>
var vm = new Vue({
el: '#example',
data: {
currentView: 'home'
},
components: {
home: { /* ... */ },
posts: { /* ... */ },
archive: { /* ... */ }
}
})
<home v-on:eventFromHome=""></home>
<archive v-on:eventFromArchive=""></archive>
<component
v-bind:is="currentView"
v-on:eventFromHome=""
v-on:eventFromArchive="">
</component>
Upvotes: 2
Views: 4501
Reputation: 10390
Since Vue.js 2.4, v-on
has an object syntax that allows dynamic event bindings.
With that, the solution is much more elegant:
var vm = new Vue({
el: '#example',
data: {
currentView: {
component: 'home',
events: {}, // <-- put listeners here
}
},
components: {
home: { /* ... */ },
posts: { /* ... */ },
archive: { /* ... */ }
}
})
<component v-bind:is="currentView.component" v-on="currentView.events"></component>
Upvotes: 5
Reputation: 3356
In my opinion the best practice is some thing like following approach. the idea is building a directive that attaches some listeners and handlers to dynamic components. thanks Javier Lecuona for his idea:
<template>
<div>
<component :is="component" v-bind="dynamicProps" v-dynamic-events="knownEvents"></component>
</div>
</template>
<script>
import CoolComponent from './cool-component.vue';
export default {
directives: {
DynamicEvents: {
bind: function (el, binding, vnode) {
const allEvents = binding.value;
allEvents.forEach((event) => {
// register handler in the dynamic component
vnode.componentInstance.$on(event, (eventData) => {
// when the event is fired, the proxyEvent function is going to be called
vnode.context.proxyEvent(event, eventData);
});
});
},
unbind: function (el, binding, vnode) {
vnode.componentInstance.$off();
},
},
},
data() {
return {
component: CoolComponent,
dynamicProps: {
isThisCool: true,
},
knownEvents: ['event-1', 'event-2']
};
},
methods: {
proxyEvent(eventName, eventData) {
// called by the custom directive
// do whatever you please with the event :)
}
}
};
</script>
Upvotes: 2
Reputation: 55644
You can just add both @eventFromHome
and @eventFromArchives
to the dynamic component:
<component
:is="currentView"
@eventFromHome="eventHandlerFoo"
@eventFromArchive="eventHandlerBar"
></component>
Upvotes: 2