Kevin W.
Kevin W.

Reputation: 101

Vue - define event handlers in array of dynamic components

I want do create some some different components by looping through an array of components like in my example. But I want to create different event handlers for each component. How can I define them in my componentData Array and bind them while looping?

componentData: [
   { name: TestPane, props: { data: "hello" }, id: 1 },
   { name: TestPane, props: { data: "bye" }, id: 2 },
],
]
<div v-for="component in componentData" :key="component.id">
   <component v-bind:is="component.name" v-bind="component.props">
   </component>
</div>

Upvotes: 5

Views: 5695

Answers (2)

Boussadjra Brahim
Boussadjra Brahim

Reputation: 1

Add method names to your array like :

componentData: [
   { name: TestPane, props: { data: "hello" }, id: 1, method:"method1" },
   { name: TestPane, props: { data: "bye" }, id: 2 ,method:"method2"},
],

in template :

  <component ... @click.native="this[component.method]()">

or add another method called handler which runs the appropriate component method :

 <component ... @click.native="handler(component.method)">
methods:{
  handler(methodName){
   this[methodName]();
 }
...
}

if the events are emitted from components, you should add their names and bind them dynamically :

componentData: [
   { name: TestPane, props: { data: "hello" }, id: 1,event:'refresh', method:"method1" },
   { name: TestPane, props: { data: "bye" }, id: 2 ,event:'input',method:"method2"},
],
<component ... @[component.event]="handler(component.method)">

Upvotes: 3

Bruno Francisco
Bruno Francisco

Reputation: 4240

You can use the v-on directive. Let's understand how Vue bind your event listeners to the component first:

When you add a @input to a componnet what you are actualy doing is v-on:input. Did you notice the v-on over there? This means that you are actually passing an 'object of listeners' to the component.

Why not pass all of them in one go?

<template>
  <section>
    <div v-for="component in componentData" :key="component.id">
      <component v-bind:is="component.name" v-bind="component.props" v-on="component.on">
    </component>
</div>
  </section>
</template>

<script>
export default {
  data: () => ({
    componentData: [
      { name: TestPane, props: { data: "hello" }, id: 1, on: { input: (e) => { console.log(e) } } },
      { name: TestPane, props: { data: "bye" }, id: 2, on: { input: (e) => { console.log(e); } } },
    ],
  })
}
</script>

As you could guess you can listen to the events now inside of on object. You can add more if you would like as well:

{ 
  name: TestPane,
  props: { data: "hello" },
  id: 1,
  on: { 
    input: (e) => { console.log(e) },
    hover: (e) => { console.log('This component was hovered') }
  } 
}

Upvotes: 13

Related Questions