1

Using cue-cli 3. Is it possible to do this (router.js):

axios.get( `${process.env.VUE_APP_API_DOMAIN}/wp-json/api/v1/routes`).then( r => r.data ).then(routes => {
    routes.pages.forEach( (e) => {
        router.addRoutes([
            {
                path: `/${e.slug}`,
                component: e.template,
            },
        ]);
    });
});

e.template is a string 'Default' and of course VueJS says: route config "component" for path: /privacy-policy cannot be a string id. Use an actual component instead. Tried with Vue.component(e.template) no luck.

What I want to do here is create dynamic routes based on XHR response.

Here is all router.js code:

import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
import Default from './views/Default.vue'
import Test from './views/Test.vue'
import axios from "axios";

Vue.use(Router);

const router = new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
  ]
});

axios.get( `${process.env.VUE_APP_API_DOMAIN}/wp-json/api/v1/routes`).then( r => r.data ).then(routes => {
    routes.pages.forEach( (e) => {
        router.addRoutes([
            {
                path: `/${e.slug}`,
                component: e.template,
            },
        ]);
    });
});

export default router;
0

2 Answers 2

1

Currently I ended up with this solution:

function getComponent(name) {

    let component = null;

    switch(name)
    {
        case 'Default':
            component = Default;
            break;

        case 'Test':
            component = Test;
            break;
    }

    return component;

}

axios.get( `${process.env.VUE_APP_API_DOMAIN}/wp-json/api/v1/routes`).then( r => r.data ).then(routes => {
    routes.pages.forEach( (e) => {
        router.addRoutes([
            {
                path: `/${e.slug}`,
                component: getComponent(e.template),
            },
        ]);
    });
});

Another one more cleaner solution:

const components = { Default, Test }

axios.get( `${process.env.VUE_APP_API_DOMAIN}/wp-json/api/v1/routes`).then( r => r.data ).then(routes => {
    routes.pages.forEach( (e) => {
        router.addRoutes([
            {
                path: `/${e.slug}`,
                component: components[e.template],
            },
        ]);
    });
});
Sign up to request clarification or add additional context in comments.

Comments

1

If e.template stores the template string,

You should wrap it as one options object like {template: e.template, props: {}, data: function () {} }, then call Vue.extend to construct the component.

or you can ignore Vue.extend because Vue will call Vue.extend to construct the component automatically.

Check the usage at Vue Guide: Vue.component

Edit as the OP states e.tempate is one component name:

if e.template is the name of component, uses Vue.component(e.template).

Vue.config.productionTip = false
const router = new VueRouter({
  routes: [
  ]
})

Vue.component('test', {
  template: '<div>I am Predefined component -> {{index}}</div>',
  props: ['index']
})

let routerIndex = 1
setInterval(()=> {
  let newComponent = routerIndex%2 ? {template: '<div>I am User -> {{index}}</div>', props: ['index']} : Vue.component('test')
  
  router.addRoutes([{
    path: '/Test' + routerIndex,
    name: 'Test' + routerIndex,
    component: newComponent,
    props: { index: routerIndex }
  }])
  console.log('add route = ', '/Test' + routerIndex, ' by ', routerIndex%2 ? 'options object' : 'Vue.component')
  routerIndex++
}, 2000)

Vue.use(VueRouter)
app = new Vue({
  el: "#app",
  router,
  data: {
    routeIndex: 0
  },
  watch: {
    routeIndex: function (newVal) {
      this.$router.push({'name': 'Test'+newVal})
    }
  }
})
div.as-console-wrapper {
  height: 100px;
}
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
    <p>Current Route Index: {{routeIndex}}</p>
    Test Route: <input v-model="routeIndex" type="number">
    <router-view></router-view>
</div>

10 Comments

Yes e.template is a string coming from backend, and I have tried: component: {template: e.template, props: {}, data: function () {} }, no avail.
Yes it's valid, but it;s string. id: 2 slug: "sample-page" template: "Test" title: "Sample Page" type: "page"
I mean e.template is a string of component name, not a Template HTML. For example e.template is 'Test' and component is imported like this: import Test from './views/Test.vue'
if so , change it Vue.component(e.template)
Tried that long time before posted this question :) It doesn't renders anything.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.