Incorporating Vue Component According to URL Parameters Dynamically

Is there a way to dynamically import a vue component based on a path provided in the URL parameters? For example, if <host>/<path> is entered into the browser, I would like to load a vue component located at <path>.vue.

In my routes.js file, I have set up a route to handle nested paths:

  { path: 'object/:catchAll(.*)*', component: BaseObject }

This route redirects to the BaseObject component:

<template>
  <div>
    <component :is="componentFile" />
  </div>
</template>
<script>
import { mapState, mapActions } from 'vuex'

export default {
  name: 'BaseObject',
  data () {
    return {
      componentPath: '',
      address: ''
    }
  },
  methods: {
    importComponent (path) {
      return () => import(`./${path}.vue`)
    }
  },
  computed: {
    componentFile () {
      return this.importComponent(this.componentPath)
    }
  },
  created () {
    const params = this.$route.params.catchAll
    console.log(params)
    this.address = params.pop()
    this.componentPath = params.join('/')
  }
}
</script>

When I go to

http://localhost:8080/#/object/action
, I expect the component located at ./action.vue to be loaded. However, instead of loading the component, I am encountering the following errors:

runtime-core.esm-bundler.js?9e79:38 [Vue warn]: Invalid VNode type: undefined (undefined) 
  at <Anonymous> 
  at <BaseObject onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< null > > 
  at <RouterView> 
  at <QPageContainer> 
  at <QLayout view="lHh Lpr lFf" > 
  at <MainLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy {$i18n: {…}, $t: ƒ, …} > > 
  at <RouterView> 
  at <App>

and

Uncaught (in promise) Error: Cannot find module './.vue'
        at app.js:416

Does anyone have a solution for this issue?

Answer №1

There seem to be a couple of issues with the code you provided...

  1. One problem lies in your "catch all" route definition

    { path: 'object/:catchAll(.*)*', component: BaseObject }
    . When navigating to URL
    http://localhost:8080/#/object/action
    , the "object" part is matched, and the catchAll parameter will only contain the item "action". As a result, the created hook will remove this single item, leaving the params array empty, causing componentPath to also be empty (leading to the error message Cannot find module './.vue')

  2. In Vue 3, the previous async component syntax (() => import(`./${path}.vue`)) has been deprecated. It is now recommended to use the defineAsyncComponent helper when creating async components (resulting in the Vue warning Invalid VNode type: undefined)

To address these issues, your BaseObject should be modified as follows:

<template>
  <div>
    <component :is="componentFile" />
  </div>
</template>
<script>
import { defineComponent, defineAsyncComponent } from "vue";

export default defineComponent({
  name: "BaseObject",
  data() {
    return {
      componentPath: "",
      address: "",
    };
  },
  methods: {},
  computed: {
    componentFile() {
      return defineAsyncComponent(() =>
        import(`../components/${this.componentPath}.vue`)
      );
    },
  },
  created() {
    const params = this.$route.params.catchAll;
    console.log(this.$route.params);
    // this.address = params.pop();
    this.componentPath = params.join("/");
  },
});
</script>

Check out the working demo here

Additionally, it's worth noting that defining a "catch all" route in this manner can be risky as it matches all routes like - /object/action, /object/action/dd, /object/action/dd/bb, where those components may not exist. Consider restricting to one level of nesting for safety...

Answer №2

It seems like you are utilizing Webpack for bundling your application and resolving JS modules. Referencing the documentation at https://webpack.js.org/api/module-methods/#import-1, the use of import() results in a promise, operating asynchronously. It is essential to first resolve this promise before utilizing the component.

methods: {
  async getComponentFile() {
    const component = await this.importComponent(this.componentPath);
    return component;
  }
},

Answer №3

Avoid taking the easy way out!

<component :is="componentFile" />
export default {
 name: 'BaseObject',

 components: {
  firstComponent: () => import('...'),
  secondComponent: () => import('...'),
  thirdComponent: () => import('...')
 }

 computed: {
  componentFile () {
   return this.detectComponentBasedPath()
  }
 },

 methods: {
  detectComponentBasedPath () {
   ...
  }
 }
}
</script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Transforming API Response into a structured format to showcase a well-organized list

When I make an API call for a list of properties, the data comes back unorganized. Here is how the data from the API looks when stored in vuex: posts:[ { id: 1; title: "Place", acf: { address: { state: "Arkansas", ...

Different ways to separate an axios call into a distinct method with vuex and typescript

I have been working on organizing my code in Vuex actions to improve readability and efficiency. Specifically, I want to extract the axios call into its own method, but I haven't been successful so far. Below is a snippet of my code: async updateProf ...

What is the solution to resolving the error message "Uncaught ReferenceError: Pusher is not defined" in Vue.js 2?

Whenever I try to launch my application, the console shows the following error: Uncaught ReferenceError: Pusher is not defined and Uncaught ReferenceError: App is not defined Despite running the following commands in my terminal: npm install and ...

VSCode - when indenting, spaces are added around strings

Currently, I am utilizing Vue 3 along with Prettier in VS Code. One issue I am encountering is that when a string is on its own line, it is formatted correctly to my liking. However, the problem arises when my browser in Dev Tools renders strings with extr ...

Formula for determining the slider's span

I recently created a range slider using Vue.js It has a minimum and maximum value, assumed to be percentages as it ranges from 0 to 100. My goal is to set the minimum value at $5,000 and the maximum at $200,000, However, I struggle with math and need th ...

The concept of sharing states between components in Vuejs

Seeking advice on the optimal approach for implementing shared states between components in Vuejs. Consider scenario A: a web app displaying a modal with a boolean state show. This state should change when the modal's OK button is clicked, as well as ...

Axios could potentially neglect default headers in certain cases

In my nuxt project, I am utilizing axios for making requests. However, I have encountered an issue where the default headers are being ignored specifically on node.js. When I run the following code snippet on node.js: import axios from "axios"; ...

Tips for incorporating auth0 into a vue application with typescript

Being a beginner in TypeScript, I've successfully integrated Auth0 with JavaScript thanks to their provided sample code. However, I'm struggling to find any sample applications for using Vue with TypeScript. Any recommendations or resources would ...

Verify whether a variable includes the tag name "img."

Currently, I am working with a variable that holds user input in HTML format. This input may consist of either plain text or an image. I am looking to determine whether the user has entered an image or just simple text. Here is an example of user entry: t ...

Vue.js - Capturing a scroll event within a vuetify v-dialog component

Currently, I am working on a JavaScript project that involves implementing a 'scroll-to-top' button within a Vuetify v-dialog component. The button should only appear after the user has scrolled down by 20px along the y-axis. Within the v-dialog, ...

Without specifying an element, the Vue3 Composition API PerfectScrollbar Plugin cannot be initialized

I'm currently facing an issue while developing a Vue3 Perfect Scrollbar plugin. The problem arises when I try to initialize the object, resulting in the following error: Error: no element is specified to initialize PerfectScrollbar The code for the ...

Having trouble transferring data to an object in VueJS

Is there a way to properly capture the uploaded file in FilePond, as the base64 data of the file is not being transferred to my object? Any suggestions on how to resolve this issue? Within the template: <FilePond v-on:addfile="catch" /> Inside ...

Navigating to URL with Query String correctly using Express

Below is the code I currently have: app.get('/', function (req, res) { req.query.searchQuery = 'test2' res.redirect('/search'); }); app.get('/search/', function (req, res) { var searchQuery = req.query.search ...

What is the best way to handle waiting for an API call in JavaScript export?

In my Vue app, I've set up my firestore app initialization code as shown below: if (firebase.apps.length) { firebase.app() } else { firebase.initializeApp(config) } export const Firestore = firebase.firestore() export const Auth = firebase.auth() ...

Access the filtered data with Vuex and Firestore to display the results

I am looking to enhance my project by implementing a filtering feature. I currently have a buttons component that will trigger the filter search. When I click the restaurant button, it should display the shops with a "Restaurant" value in Firestore. Conv ...

What is the best way to uninstall the Google Translation Plugin when transitioning to a new Vue component?

I'm facing a minor issue as I develop a website builder. It consists of two main parts: the builder and the preview section. Within the preview, I've included the Google Translation plugin: onMounted(() => { new google.translate.TranslateEle ...

Adding an item to a sleek carousel

Adding items to a Slick carousel in a vue.js demo is proving to be a bit tricky. When I try to use the refresh() function after adding an item, it doesn't seem to work as expected even though the item is successfully added with vue.js. //Attempting to ...

After manipulating the array, Vue fails to render the input fields generated by the v-for directive

After setting the value externally, Vue component won't re-render array items. The state changes but v-for element does not reflect these changes. I have a component that displays items from an array. There are buttons to adjust the array length - &a ...

Working with dynamic checkbox values in VueJS 2

In my project using VueJS 2 and Vuetify, I am creating a subscription form. The form is dynamic and fetches all the preferences related to a subscription from the server. In the example below, the preferences shown are specifically for a digital magazine s ...

Can you provide a guide on setting up and utilizing mathlive within NuxtJS?

Can anyone assist me? I am trying to figure out why my code is not working or if I have implemented it incorrectly. I used npm i mathlive to obtain input. However, following the instructions for implementing nuxt plugins in the documentation has not yield ...