2

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?

Dynamic component

var vm = new Vue({
  el: '#example',
  data: {
    currentView: 'home'
  },
  components: {
    home: { /* ... */ },
    posts: { /* ... */ },
    archive: { /* ... */ }
  }
})

<component v-bind:is="currentView"></component>

Static component

var vm = new Vue({
  el: '#example',
  data: {
    currentView: 'home'
  },
  components: {
    home: { /* ... */ },
    posts: { /* ... */ },
    archive: { /* ... */ }
  }
})

<home v-on:eventFromHome=""></home>
<archive v-on:eventFromArchive=""></archive>

Temporary answer

<component 
    v-bind:is="currentView"
    v-on:eventFromHome=""
    v-on:eventFromArchive="">
</component>
6
  • You can just add both @eventFromHome and @eventFromArchives to the dynamic component. Commented Jun 1, 2017 at 20:13
  • So it would be something like <component v-on:eventFromHome="" v-on:eventFromArchive="" v-bind:is="currentView"></component> ? That is what you are saying ? Commented Jun 1, 2017 at 20:14
  • Yep, that's correct. There might be a more elegant solution, but nothing's coming to mind. Commented Jun 1, 2017 at 20:15
  • Well, in the case we have let's say 30 events it will look bad for sure :/ ... Commented Jun 1, 2017 at 20:15
  • 2
    If you have 30 events you might want to use a centralized event bus. vuejs.org/v2/guide/… Commented Jun 1, 2017 at 20:18

3 Answers 3

5

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

1 Comment

In this case, each event inside events, would be 'event-emitted-name' : this.parentUpdateFunction
2

You can just add both @eventFromHome and @eventFromArchives to the dynamic component:

<component 
  :is="currentView"
  @eventFromHome="eventHandlerFoo" 
  @eventFromArchive="eventHandlerBar"
></component>

Comments

2

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>

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.