3

In VueJS im trying to setup a scenario where the component used is determined by the url path without having to statically map it.

e.g.

router.beforeEach(({ to, next }) => {


  FetchService.fetch(api_base+to.path)
    .then((response) => {
      router.app.$root.page = response

      // I'd like to specify a path and component on the fly 
      // instead of having to map it

      router.go({path: to.path, component: response.pageComponent})

    })
    .catch((err) => {
      router.go({name: '404'})
    })

})

Basically, I'd like to be able to create a route on the fly instead of statically specifying the path and component in the router.map

Hope that make sense. Any help would be appreciated.

patskot
  • 165
  • 2
  • 12
  • [router.go](https://github.com/vuejs/vue-router/blob/1.0/docs/en/api/go.md) programatically navigate to a new route, is that you wan to do dynamically? – Saurabh Dec 08 '16 at 00:43
  • @saurabh I'd like to be able to specify the URL/path and component dynamically. The scenario is, I use the path to generate an API call to an external CMS, if the page exists it returns a response with the name of the component that should be used for that page. – patskot Dec 08 '16 at 01:37
  • But with `router.go`, you want to redirect to that page, right? – Saurabh Dec 08 '16 at 01:40
  • @saurabh yes, I'd like to redirect to the page/load a new component – patskot Dec 08 '16 at 01:42

2 Answers2

2

I think that what you're trying to archive is programmatically load some component based on the current route.

I'm not sure if this is the recommended solution, but is what comes to my mind.

  1. Create a DynamicLoader component whit a component as template
<template>
<component :is="CurrentComponent" />
</template>
  1. Create a watch on $route to load new component in each route change
<script>
export default {
  data() {
    return {
      CurrentComponent: undefined
    }
  },
  watch: {
    '$route' (to, from) {
      let componentName = to.params.ComponentName;
      this.CurrentComponent = require(`components/${componentName}`);
    }
  },
  beforeMount() {
    let componentName = this.$route.params.ComponentName;
    this.CurrentComponent = require(`components/${componentName}`);
  }
}
</script>
  1. Register just this route on your router
{ path: '/:ComponentName', component: DynamicLoader }

In this example I'm assuming that all my componennt will be in components/ folder, in your example seems like you're calling an external service to get the real component location, that should work as well.

Let me know if this help you

AldoRomo88
  • 2,056
  • 1
  • 17
  • 23
  • Thanks @AldoRomo88, this is exactly what I was looking for, I wasn't aware of the `:is` attribute. I was able to add the query into the process to get the `componentName` and all is working fine! The only other thing (not sure if this should be a new question) is if there is a way to check if a route is set for a certain path? e.g. before querying the CMS with a path, check if there is a route that uses said path. Is there a way of doing something like `if(this.$route.go(path))`? – patskot Dec 09 '16 at 00:08
  • 1
    You could do that using navigation guards as in your initial example, just check this `if(to.matched.length)` that means that at least one static route matched with the given path – AldoRomo88 Dec 09 '16 at 14:10
1

As par the documentation of router.go, you either need path you want to redirect to or name of the route you want to redirect to. You don't the component.

Argument of router.go is either path in the form of:

{ path: '...' }

or name of route:

{
  name: '...',
  // params and query are optional
  params: { ... },
  query: { ... }
}

so you dont need to return component from your API, you can just return path or name of route, and use it to redirect to relevant page.

You can find more details here to create named routes using vue-router.

Saurabh
  • 71,488
  • 40
  • 181
  • 244
  • Thanks @saurabh, so router.go is probably not what I want to use. I still need the ability to specify the component dynamically. For example, if the fetch result has `result.template === 'SimplePage'` it should then use the SimplePage component but keep the original path (where a named route has both path and component hard coded). – patskot Dec 08 '16 at 02:40
  • @patskot: I am not sure of that, but if you just want to render a component, without changing route, you can use [$mount](https://vuejs.org/v2/api/#vm-mount), so you will get component from API, you convert it to class as explained [here](http://stackoverflow.com/questions/1366127/instantiate-a-javascript-object-using-a-string-to-define-the-class-name) and than mount it to HTML element you want to, How this sound? – Saurabh Dec 08 '16 at 03:12