Can i split up children routes into component files? - vue.js

When learning the Vue Router on https://router.vuejs.org/, the section on nested routes shows how to declare children routes.
But the only way it shows it being possible is declaring all of them in the single Router file. So if i were to build a somewhat large app index consisting of several independent apps, and i wanted each of those apps to have routing and links pointing to whatever pages they use, then it would be inconsistent and hard to maintain if it were mandated that those routes were all to be declared in the main router config. I guess i'm looking for a more separation-of-concerns approach.
Let's say if one of my apps was a Todo App whose main component is defined in TodoApp.vue, the kind of thing i'm hoping for is that i could define all the routes for this Todo app in its .vue file, and then the main router config would import it, and treat those routes as children of the main /todo route, assuming that /todo is the path to the Todo App.
For example, let's say this is an excerpt of my Router definition, showing that Todo is one of my apps that has some subnavigation going on:
const router = new Router({
base: process.env.BASE_URL,
routes: [
{
path: '/todo',
name: 'TodoApp',
component: Todo
children: [{
path: 'create-task',
component: TodoCreateTask,
},{
path: 'edit-tasks',
component: TodoEditTask,
},{
path: 'create-task',
component: TodoCreateTask,
}]
]
});
I am wondering if it would be possible to remove the children part from this declaration, move it into the Todo component file, and then do some kind of an import here?

You can simply store children routes in a separate file as a regular array, for example:
subroutes.js
// import the components that are being referenced
export default [{
path: 'create-task',
component: TodoCreateTask,
},{
path: 'edit-tasks',
component: TodoEditTask,
},{
path: 'create-task',
component: TodoCreateTask,
}]
App.vue
import subroutes from './subroutes';
const router = new Router({
base: process.env.BASE_URL,
routes: [
{
path: '/todo',
name: 'TodoApp',
component: Todo,
children: subroutes,
}
]
});

Related

Vue-router is changing the url but not re-rendering the component

First of all I've checked and history mode is turned on, I invoke vue-router like so:
const router = new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: routes,
});
The current route I am on is /page/item/8, and I am redirecting to /page/item/9. Currently the url changes but the page does not re-render leaving me on the same view I had before.
This redirection is done like so:
this.$router.push({ name: 'PageItem', params: { itemId: '9' }}).catch(err => {
// Stop Vue.router throwing an error if a user clicks on a notification with the same route.
if (err.name !== 'NavigationDuplicated') {
this.$logger.debug.log(err);
}
});
The route in question like so:
import PageWrapper from '#/layouts/PageWrapper';
export default [
{
path: '/page',
name: 'page',
component: PageWrapper,
children: [
... Other Routes ...
{
component: () => import(/* webpackChunkName: "page-item" */'#/pages/PageItem'),
name: 'PageItem',
path: '/item/:itemId/:view?',
},
],
},
];
Any ideas, I've tweaked the code to remove identifying code so apologies if it looks a bit odd.
Only the itemId route param is changing. In this situation, since the same route components are being used before and after the transition, vue-router will reuse the existing route components; they don't get destroyed and recreated. So if you're loading data in the component created or mounted hooks then they won't be called again after the route changes. Instead you need to use beforeRouteUpdate or watch $route for changes.
If you want to force the component to be destroyed and recreated (not recommended) then you need to key the <router-view> on the route:
<router-view :key="$route.fullPath">
Read the Data Fetching guide for more information.

What does the name option in routes:[] actually refer to (Vue.js CLI3)?

Ìm new to vue.js and I#m practicing routing right now.
My router.js looks like this:
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
Vue.use(Router)
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
},
{
path: '/myView',
name: 'myView',
component: () => import('./views/myView.vue')
}
]
})
Now I thought the name option referred to the name I've given the "component".
For example, I tried out the following with "myView" view:
<template>
<div>
<myWorld placeholder="tester"/>
</div>
</template>
<script>
import myWorld from '#/components/myWorld.vue'
export default {
name: 'sklfdjns',
components: {
myWorld
}
}
</script>
As you can see, the name is just gibberish. If the name option in the router really referenced this name in the component, Id expect it to fail.
But it doesnt. Everything works just fine.
Then I tried out changing the name in the router option, but nothing changed as well.
So what does this name option actually do?
Unfortunately, the official Documentation wasnt helpful for me either..
https://router.vuejs.org/guide/essentials/named-routes.html
As mentioned in docs router names are different than component names
purpose of named routes is to navigate without giving full URL i.e just by giving name and it's not reference to component name it's just name of your route
router.push({ name: 'user', params: { userId: 123 }})
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
both will navigate to user route which is '/user/:userId'
As stated in the docs you posted, the name can be added for convenience. This can be helpful for longer paths or for iterating your routes into a menu for example.
To call such a route you then can use the name instead:
<router-link :to="{ name: 'home' }">home</router-link>
Another convenience example where i used the names before is iterating it into a menu with $route.name, you want readable names there.
Adding to Answer 1... the name mostly used when you want to push users from one page to another after something has happened
this.$router.push({name:'details'})
if the details name does not exist, you get an error
and also when you are also specific to a particular route, according to the first answer
the name in the component specifics name of that component.
This is useful in vue devtool for debugging, or when you want to render a component recursively, you have to set a name for the component. For example, you want to render component comment inside the template of a comment (to display sub-comment).
The name in router is name of that route.
For example:
you have a route like this
{
path: '/',
component: Home
},
when you want to go to the root page, you do some thing like this, right?
this.$router.push('/')
What if I want to change the root path to /admin?
I will have to find all this code this.$router.push('/') and replace the path? No way!
Instead, I will specific a route name name: 'root', and navigate through routes by name.
{
path: '/',
name: 'root',
component: Home
}
this.$router.push({ name: 'root' });
Once I want to change the route path, I just change the path in router.js
The name in component property and the one from route has no relation.

Nested routes not rendering in router-view

I'm setting up what is going to be a large system, so I want to have decentralised router.js files for every module. Each of them would have routes arrays declarations that would be pushed to the main routes array.
So for now I have a kind of root of routes file, which have the VueRouter instances and settings, and it imports the first level of route.js files to build the routes array.
main routes.js file
import DashboardRoutes from './views/dashboard/routes'
Vue.use(Router)
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{// Root public site
path: '/',
component: () => import('./views/pages/Index'),
children: PagesRoutes
},
name: 'page_error',
path: '*',
component: () => import('./views/error/Error')
}
].concat(
DashboardRoutes
)
})
module (first level) routes.js file
import InventoryRoutes from './inventarios/routes'
const routes = {
path: '/panel',
component: () => import('./Index'), // This Index has a layout with a router-view in it
children: [
// Inicio del panel
{
name: 'dashboard',
path: '',
component: () => import('./Dashboard'),
}
].concat(
InventariosRoutes
)
}
export default routes
Components (second level) routes.js file
const routes = {
path: 'inventario',
name: 'panel_inventario',
component: { template: '<router-view/>' },
children: [
// Productos y servicios
{
name: 'panel_inventarios_productos-servicios',
path: 'productos-servicios',
component: () => import('./productos-servicios/ProductosServiciosHome'),
},
]
}
export default routes
In the components tree of vue-tools I see an AnnonymousComponent in the place where my children's router-view should be.
Update
I just create an external component to name it and check if it's being rendered like this
Components (second level) routes.js file
const loader = {
template: `
<div class="InventarioLoader">
<router-view></router-view>
</div>
`,
name: 'InventarioLoader'
}
const routes = {
path: 'inventario',
name: 'panel_inventario',
component: loader,
children: [
// children go here
]
}
Now I see my InventarioLoader component, but I still don't see my children components rendered in it
Update
I see this error on the console
You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.
You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.
By default, Vue does not compile string templates. This is for performance reasons.
Since the runtime-only builds are roughly 30% lighter-weight than their full-build counterparts, you should use it whenever you can
See https://v2.vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only
Either create a real single-file component or use a render function
import Vue from 'vue'
const RouterView = Vue.component('router-view')
const loader = {
name: 'InventarioLoader',
render (createElement) {
return createElement(RouterView)
}
}
Apparently now you can't point a route to a inline component like {template:'<router-view/>} and my solution was to create a loader component with that template and use it on the parent route

How to get component name or the python from vue-router?

I use vue-router like:
export default new Router({
routes: [
{
path: '/',
components: {
navbar: Navbar,
subnavbar: SubNavbar,
main: WhoisPage //********
}
}
In my component WhoisPage.vue, I want to know the component path or the main module(which is //****** line) use which component?
How to do it with vue or vuex?
First of all, there is no "components" property on vue-router.
You need to use "component" property to inject your shell component (in this case, it looks like WhoisPage) then you can call your sub-components to build your page inside your shell component.
If you want to change your sub-components based on route automatically, you can send their names as string and render in your shell-component.
// in your router config.
export default new Router({
routes: [
{
path: '/',
component: WhoisPage,
meta: {
navbar: 'NavbarComponent'
}
}
]
})
<!-- in your shell component, ofc your navbar needs to be imported -->
<component :is="$route.meta.navbar"></component>
Not sure i correctly answered what you need tho.

Issue rendering child views in Vue with Vue Router

I'm having trouble getting my child views to render in Vue.
My main.js file looks like this
import DashboardProducts from './components/Dashboard/DashboardProducts'
import DashboardSettings from './components/Dashboard/DashboardSettings'
Vue.use(VueRouter)
Vue.use(Vuex)
const routes = [
{ path: '/activate', component: Activate },
{ path: '/dashboard/:view', component: Dashboard,
children: [
{ path: 'products', component: DashboardProducts },
{ path: 'settings', component: DashboardSettings }
]
},
{ path: '/login', component: Login },
{ path: '/account', component: UserAccount }
];
const router = new VueRouter({
routes // short for routes: routes
});
export default router;
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
render: h => h(App)
});
As you can see I have imported the components and get no errors. I have also added them as children of Dashboard and set their paths.
In my Dashboard.vue view I do this
<template>
<div>
<dashboard-nav></dashboard-nav>
<!-- Will display product and settings components -->
<router-view></router-view>
</div>
</template>
<script>
import DashboardNav from '../components/Dashboard/DashboardNav'
export default {
name: 'Dashboard',
components: {
DashboardNav
}
};
</script>
<style>
</style>
Urls are matching but no components are rendering. What am I missing?
Here is a JSFiddle of pretty much what I'm going for https://jsfiddle.net/dtac5m11/
It seems to be working fine there but I'm also using single file components in my app so it may be a little different?
Again, the issue is getting the child components to render when their routes match. Currently no components are being mounted.
UPDATE:
I am getting the DashboardProducts component to render but can't get DashboardSettings to render.
Thanks!
{ path: '/dashboard/:view', component: Dashboard,
At first, for what purpose do you add :view after dashboard path? If you are using this one for children path as a parameter, it is an issue. It is the reason, why your children component are not rendering. Because, :view is for dynamic routes. /dashboard/:view is equivalent to /dashboard/* and it means that after /dashboard there can be any route and this route will render Dashboard component. And your children paths /dashboard/products and /dashboard/settings will always match /dashboard/:view and render parent component-Dashboard.
So, in your case, your routes for children components are known. So you do not need to use :view.
More, https://router.vuejs.org/en/essentials/dynamic-matching.html.