Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue js import components dynamically

I have the following parent component which has to render a list of dynamic children components:

<template>
  <div>
    <div v-for="(componentName, index) in supportedComponents" :key="index">
      <component v-bind:is="componentName"></component>
    </div>
   </div>
 </template>

<script>
const Component1 = () => import("/components/Component1.vue");
const Component2 = () => import("/components/Component2.vue");
export default {
  name: "parentComponent",
  components: {
    Component1,
    Component2
  },
  props: {
    supportedComponents: {
      type: Array,
      required: true
    }
  }
};
</script>

The supportedComponents property is a list of component names which I want to render in the parent conponent.

In order to use the children components in the parent I have to import them and register them.

But the only way to do this is to hard code the import paths of the components:

const Component1 = () => import("/components/Component1.vue");
const Component2 = () => import("/components/Component2.vue");

And then register them like this:

components: {
  Component1,
  Component2
}

I want to keep my parentComponent as generic as possible. This means I have to find a way to avoid hard coded components paths on import statements and registering. I want to inject into the parentComponent what children components it should import and render.

Is this possible in Vue? If yes, then how?

like image 991
whitefang1993 Avatar asked Sep 24 '19 12:09

whitefang1993


People also ask

How do I dynamically load components in Vue?

To make the component dynamic, we can bind it to a set property with the v-bind directive. Your component is now bound with the component property in the data. If you switch the component to Test2 , it will automatically mount the Test 2 component. Test it out on your browser.

How do I import components to Vue?

STEP 01: First, Import the Child Component into the Parent Component inside script tag but above export default function declaration. STEP 02: Then, Register the Child Component inside the Parent Component by adding it to components object. STEP 03: Finally, Use the Child Component in the Parent Component Template.

Is Vue synchronous or asynchronous?

You might know Vue updates reactively: when you change a value, the DOM is automatically updated to reflect the latest value. Vue does these updates asynchronously. In contrast, a test runner like Jest runs synchronously. This can cause some surprising results in tests.


3 Answers

You can load the components inside the created lifecycle and register them according to your array property:

<template>
    <div>
        <div v-for="(componentName, index) in supportedComponents" :key="index">
            <component :is="componentName"></component>
        </div>
    </div>
</template>

<script>
    export default {
        name: "parentComponent",
        components: {},
        props: {
            supportedComponents: {
                type: Array,
                required: true
            }
        },
        created ()  {
            for(let c=0; c<this.supportedComponents.length; c++) {
                let componentName = this.supportedComponents[c];
                this.$options.components[componentName] = () => import('./' + componentName + '.vue');
            }
        }
    };
</script>

Works pretty well

like image 65
Launemax Avatar answered Oct 01 '22 15:10

Launemax


Here's a working code, just make sure you have some string inside your dynamic import otherwise you'll get "module not found"

       <component :is="current" />
    export default {  data () {
    return {
      componentToDisplay: null
    }
  },
  computed: {
    current () {
      if (this.componentToDisplay) {
        return () => import('@/components/notices/' + this.componentToDisplay)
      }
      return () => import('@/components/notices/LoadingNotice.vue')
    }
  },
  mounted () {
    this.componentToDisplay = 'Notice' + this.$route.query.id + '.vue'
  }
}
like image 35
Ashraf Mohamed Avatar answered Oct 01 '22 16:10

Ashraf Mohamed


Resolving dynamic webpack import() at runtime

You can dynamically set the path of your import() function to load different components depending on component state.

<template>
  <component :is="myComponent" />
</template>

<script>
export default {
  props: {
    component: String,
  },

  data() {
    return {
      myComponent: '',
    };
  },

  computed: {
    loader() {
      return () => import(`../components/${this.component}`);
    },
  },

  created() {
    this.loader().then(res => {
      // components can be defined as a function that returns a promise;
      this.myComponent = () => this.loader();
    },
  },
}
</script>

Note: JavaScript is compiled by your browser right before it runs. This has nothing to do with how webpack imports are resolved.

like image 25
MarcRo Avatar answered Oct 01 '22 17:10

MarcRo