I'm using the vue-router and have a question regarding subRoutes. I would like to set up my routes so the main routes are listings and the subRoutes are things like edit/add/etc.
I want the subRoute components to replace the <router-view>
of the parent route. The way I understand the documentation and from what I've tested, it looks like I should define another <router-view>
in the parent components template for the subRoute to render into but then the user-list would remain visible.
Example routes:
'/users': {
name: 'user-list',
component(resolve) {
require(['./components/users.vue'], resolve)
},
subRoutes: {
'/add': {
name: 'add-user',
component(resolve) {
require(['./components/users_add.vue'], resolve)
}
}
}
}
Main router view:
<!-- main router view -->
<div id="app">
<router-view></router-view>
</div>
User list:
<template>
<a v-link="{ name: 'add-user' }">Add</a>
<ul>
<li>{{ name }}</li>
</ul>
</template>
Add user:
<template>
<div>
<a v-link="{ name: 'user-list' }">back</a>
<input type="text" v-model="name">
</div>
</template>
When I click on "Add", I want to be filled with the add-user template. Is this possible?
Also, can I establish a parent-child relationship between the user-list and add-user components? I would like to be able to pass props (list of users) to the add component and dispatch events back up to the user-list.
Thanks!
It sounds like those edit/add routes should not be subRoutes, simple as that.
just because the path makes it seem like nesting doesn't mean you have to actually nest them.
'/users': {
name: 'user-list',
component(resolve) {
require(['./components/users.vue'], resolve)
}
},
'users/add': {
name: 'add-user',
component(resolve) {
require(['./components/users_add.vue'], resolve)
}
}
So I played around with this for quite a bit and finally figured out how this can be achieved. The trick is to make the listing a subRoute too and have the root-level route just offer a <router-view>
container for all child components to render into. Then, move the "list loading" stuff to the parent component and pass the list to the list-component as a prop. You can then tell the parent to reload the list via events.
That's it for now, it works like a charm. Only drawback is that I have another component that I didn't really need. I'll follow up with an example when I find the time.
edit
Added an example as requested. Please note: this code is from 2016 - it may not work with current Vue versions. They changed the event system so parent/child communication works differently. It is now considered bad practice to communicate in both directions (at least the way I'm doing it here). Also, these days I would solve this differently and give each route it's own module in the store.
That said, here's the example I would have added back in 2016: Let's stick with the users example - we have a page with which you can list/add/edit users.
Here's the route definition:
'/users': {
name: 'users',
component(resolve) {
// this is what I meant with "root-level" route, it acts as a parent to the sub routes
require(['./pages/users.vue'], resolve)
},
subRoutes: {
'/': {
name: 'user-list',
component(resolve) {
require(['./pages/users/list.vue'], resolve)
}
},
'/add': {
name: 'user-add',
component(resolve) {
require(['./pages/users/add.vue'], resolve)
}
},
// etc.
}
},
users.vue
<template>
<div>
<router-view :users="users"></router-view>
</div>
</template>
<script>
/**
* This component acts as a parent and sort of state-storage for
* all user child components. It's the route that's loaded at /users.
* the list component is the actual component that is shown though, but since
* that's a sibling of the other child components, we need this.
*/
export default {
events: {
/**
* Update users when child says so
*/
updateUsers() {
this.loadUsers();
}
},
data() {
return {
users: []
}
},
route: {
data() {
// load users from server
if (!this.users.length) {
this.loadUsers();
}
}
},
methods: {
loadUsers() {
// load the users from an API or something
this.users = response.data;
},
}
}
</script>
./pages/users/list.vue
<template>
<ul>
<li v-for="user in users" :key="user.id">
{{ user.name }}
</li>
</ul>
</template>
<script>
export default {
props: ['users'],
// the rest of the component
}
</script>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With