Tim Titus
Tim Titus

Reputation: 394

Interpolate dynamic components within a v-for loop

I currently have a v-for which creates a list of components depending on an array of name values. Depending on the step === 'name' check, I'm displaying the relevant component. This method requires that I list every single possible component with a v-if and I think there should be a cleaner way to accomplish this.

    <div v-for="(step, idx) in steps" :key="idx">
      <div v-if="step === 'url'">
        <Goto @removeStep="removeStep(idx)" />
      </div>
      <div v-if="step === 'click'">
        <Click @removeStep="removeStep(idx)" />
      </div>
      <div v-if="step === 'search'">
        <Search @removeStep="removeStep(idx)" />
      </div>
      ...
    </div>

I'd rather interpolate the component directly in my for loop.

For example, something like...

 <div v-for="(step, idx) in steps" :key="idx">
   <[step.component] @removeStep="removeStep(idx)" :title="step.title" />
 </div>

My array of dynamic components would then look like:

steps: [
 {
  component: 'Goto',
  title: 'Go to Url'
 },
 {
  component: 'Click',
  title: 'Click Something'
 }
]

I do not want to have all component options in a single file component, and prefer them to remain as separate components as I have currently.

Could I accomplish the above using either some form of interpolation or a computed prop perhaps?

Upvotes: 4

Views: 3353

Answers (1)

tony19
tony19

Reputation: 138226

Vue supports dynamic components with <component is="COMPONENT_NAME">. You could register your components locally, and then bind <component>.is to the component names in your steps array:

<template>
  <div>
    <component
      :is="step.component"
      v-for="(step, idx) in steps"
      :key="step.component"
      :title="step.title"
      @remove-step="removeStep(idx)"
    />
  </div>
</template>

<script>
import Goto from './components/Goto'
import Click from './components/Click'
import Search from './components/Search'

export default {
  components: {
    Goto,
    Click,
    Search,
  },
  data() {
    return {
      steps: [
        {
          component: 'Goto',
          title: 'Go to Url',
        },
        {
          component: 'Click',
          title: 'Click Something',
        },
        {
          component: 'Search',
          title: 'Search the Internet',
        },
      ],
    }
  },
  methods: {
    removeStep(idx) {
      console.log('remove step', idx)
    },
  },
}
</script>

demo

Upvotes: 6

Related Questions