Mohsen Mirshahreza
Mohsen Mirshahreza

Reputation: 147

Dynamically adding new .vue component

I am using vue3-sfc-loader (https://github.com/FranckFreiburger/vue3-sfc-loader) to register and load .vue components that works fine:

sample 1

<div id="app">
    <ae-studio></ae-studio>
</div>
<script>
    const app = Vue.createApp({});
    app.component('ae-studio', loadVM("/components/aeStudio.vue"));
    const vueInstance = app.mount("#app");
</script>

sample 2

<template>
    <div>
        append studio header
    </div>
    <table style="width:100%;">
        <tr>
            <td style="width:50%">
                <ae-nav></ae-nav>
            </td>
            <td style="width:50%">
                <ae-docsview></ae-docsview>
            </td>
        </tr>
    </table>
</template>
<script>
    app.component('ae-nav', loadVM("/components/aeNav.vue"));
    app.component('ae-docsview', loadVM("/components/aeDocsview.vue"));    
</script>

they are working but I need to dynamically add a component to the page like this :

<template>
    <button @click="show('this is a message')">Click to add Component here</button>
    <div id="comPlace">A place for new component</div>
</template>

<script>    
    app.component('ae-test', loadVM("/components/aeTest.vue"));

    export default {
        setup(props) {
            return {
                show: (msg) => {

                    console.log(msg);
                    let cPlace = document.getElementById("comPlace");
                    cPlace.innerHTML='<ae-test>qqqqqqqqqqqqqqqqqqq</ae-test>';
                    let a = app.component('ae-test', loadVM("/components/aeTest.vue"));
                }
            };
        }
    }
</script>

Above code is not working. I tried forceUpdate but the issue not resolve. How can I resolve this? I created a repository on github that you can use it for tracking the issue.

https://github.com/mirshahreza/DynamicVueComponen

Upvotes: 1

Views: 443

Answers (1)

Salim Baskoy
Salim Baskoy

Reputation: 719

You can use component in vue 3

 <script>

      const { loadModule, vueVersion } = window["vue3-sfc-loader"];
      console.log("vueVersion", vueVersion);
      const options = {
        moduleCache: {
          vue: Vue
        },
        getFile(url) {
          return fetch(url).then((response) =>
            response.ok ? response.text() : Promise.reject(response)
          );
        },
        addStyle(styleStr) {},
        log(type, ...args) {
          console.log(type, ...args);
        }
      };
      window.loadVM = async (path) => {
        return loadModule(path, options);
      };
 
    </script>

and you can use Vue.defineAsyncComponent

<template>
  <button @click="() => showTestOneComponent('this is a message')">
    Click to add test here
  </button>
  <button @click="() => show2TestOneComponent('this is a test2 component')">
    Click to add test2 here
  </button>
  <div id="comPlace">
    <component :is="dynamicComponent" :title="title" />
  </div>
</template>

<script>
import { ref } from "vue";
export default {
  setup(props) {
    const dynamicComponent = ref();
    const title = ref();
    const showTestOneComponent = async (msg) => {
      dynamicComponent.value = Vue.defineAsyncComponent(() =>
        window.loadVM("./test.vue")
      );
      title.value = msg;
    };
    const show2TestOneComponent = async (msg) => {
      dynamicComponent.value = Vue.defineAsyncComponent(() =>
        window.loadVM("./test2.vue")
      );
      title.value = msg;
    };
    return {
      dynamicComponent,
      title,
      showTestOneComponent,
      show2TestOneComponent,
    };
  },
};
</script>

updated full code here.

Upvotes: 1

Related Questions