P
P
Pavel Lebedev2019-06-14 09:29:40
Vue.js
Pavel Lebedev, 2019-06-14 09:29:40

Multiple templates for one Vue.js component, implementation?

There are components that accept several objects with props. There are HTML files (30+ pieces) that contain different data layout.
This implementation gives an error

Cannot find module './undefined.html'
- the variable does not exist when the template is initialized
export default {
  props: {
    id: Number,
    tmplLink: String
  },
  template: require(`./${this.tmplLink}.html`)
};

Is it possible to pass the template name to this component so that the variable exists during initialization.
Also, an article was found on the subject, listing the code of the article below . The task is similar, but the author uses VUE files. When I try to execute his code, I get an error that loader is not a function.
<template>
    <component :is="component" :data="data" v-if="component" />
</template>
<script>
export default {
    name: 'dynamic-link',
    props: ['data', 'type'],
    data() {
        return {
            component: null,
        }
    },
    computed: {
        loader() {
            if (!this.type) {
                return null
            }
            return () => import(`templates/${this.type}`)
        },
    },
    mounted() {
        this.loader()
            .then(() => {
                this.component = () => this.loader()
            })
            .catch(() => {
                this.component = () => import('templates/default')
            })
    },
}
</script>

UPD#1
loader() was immediately changed to
loader() {
      return () => import(`./templates/${this.tmplLink}`);
    }

Received the following error:
Failed to resolve async component: function () {
return __webpack_require__.e(/*! import() */ 0).then(__webpack_require__.bind(null, /*! ./templates/default */ "./resources/js /makets/templates/default/index.vue"));
}
Reason: TypeError: Cannot read property 'call' of undefined

The solution from the article does not really appeal to me, because. there is a need for different templates, and not for the entire component with its own logic.
Perhaps there are solutions to these two problems?

Answer the question

In order to leave comments, you need to log in

3 answer(s)
E
Evgeny Kulakov, 2019-06-14
@kulakoff Vue.js

You are most likely getting the error because of this condition:

if (!this.type) {
  return null
}

Those. when calling this.loader you have null there.

E
Evgeniy S, 2019-06-14
@evgensenin

For this case, use render functions, just perfect.

D
Daniil Bratukhin, 2019-06-15
@dantothefuture

You can try like this (see code below). This is essentially Philipp Kühn's solution, but for your case where templates are stored in files, not components. To make it work, you need to set up a loader for html files ( raw-loader is perfect) and include the compiler in the assembly ( the "full" option ).
In theory, this can be optimized to a functional component, but for some reason it does not work in practice. Maybe my hands are crooked)

export default {
  props: {
    name: {
      type: String,
      default: 'default'
    }
  },
  computed: {
    component () {
      // Не сокращать до одной строки, иначе свойство не будет реактивным.
      const name = this.name
      return () => this.load(name)
    }
  },
  methods: {
    async load (name) {
      // В import() должен быть статический элемент (как './templates/'), иначе не заработает.
      const { default: template } = await import(`./templates/${name}.html`)
      return { template }
    }
  },
  render (h) {
    return h(this.component)
  }
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question