alecmarcus
alecmarcus

Reputation: 33

Dynamic Vue component import path using template literals

EDIT

So, the following technically answers the question, and is based on Husam's answer.

beforeCreate: function () {
  this.$options.components.Background = () =>
    import(`~/assets/img/marketing/user-group-backgrounds/user-group-bg-${this.bg}.svg`)
}

Will work as requested, fetching the background based on the bg prop. Only problem is, it is an SVG, not a .vue file, and not being passed through vue-svg-loader, so I get the error Invalid Component definition.


ORIGINAL QUESTION

I have a vue/Nuxt.js app in which we are using vue-svg-loader (documentation).

The component in question (child) retrieves several bits of data as props from an object defined in its parent (parent) component.

parent loops over the top entries in the object using v-for, generating a child for each.

Each child needs a different background image, whose path can be determined using:

`~/path/to/image/background-number-${prop-from-parent}`

Since vue-svg-loader treats SVG images as components, and it provides several benefits I would like to leverage, I am trying to devise a solution that will allow me to do something along these lines:

<template>
  <div class="child">
    <Background class="background-image" />
    <p>
      ...
    </p>
  </div>
</template>

<script>
const Background = import(`~/path/to/image/background-number-${prop-from-parent}`)

export default {
  components: {
    Background
  },
  props: {
    prop-from-parent: { type: String, required: true }
    }
  }
</script>

Doing so returns:

NuxtServerError
render function or template not defined in component: Background

I have done research and seen that the only solution seems to be of this sort:

import BackgroundOne from 'path/to/background-one.svg'
import BackgroundTwo from 'path/to/background-two.svg'
import BackgroundThree from 'path/to/background-three.svg'

export default{
  components: {
    BackgroundOne,
    BackgroundTwo,
    BackgroundThree,
  }
}

(source)

Which is just silly. I could move the background insertion logic the parent component and insert it into each child using <slot />, and it would serve my purpose, but that seems much too declarative. My list is currently 10 items long and may grow, and almost certainly will change in the future.

Upvotes: 2

Views: 1650

Answers (1)

Husam Elbashir
Husam Elbashir

Reputation: 7187

You can try this technique ..

<script>
export default {
  props: {
    prop-from-parent: { type: String, required: true }
  },
  beforeCreate: function () {
    const filePath = `~/path/to/image/background-number-${this.prop-from-parent}`
    this.$options.components.Background = require(filePath).default
  }
}
</script>

As seen here. It might work in your case.

Upvotes: 1

Related Questions