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

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.

Related

When I change the :id param in the url of my vue application, why doesn't the page reload when I press enter?

I have a vue js application that is using the vue router. I have the following route:
http://server/stores/index.html#/ViewStore/:StoreId
If I change :StoreId in the url and press enter, nothing happens. I have to hit F5 to reload the page and have it process the new :StoreId.
I am using:
<router-view :key="$route.fullPath"></router-view>
In my App.vue component.
My routes are defined in routes.js as follows:
import Home from '#/components/Home';
import EditStore from "#/components/EditStore";
import ViewStore from "#/components/ViewStore";
export const routes = [
{ path: '/', redirect: '/ViewStore/NotFound' },
{ path: '/StoreListing/:DisplayTarget', component: Home, },
{ name: 'ViewStore', path: '/ViewStore/:StoreId', component: ViewStore, },
{ name: 'EditStore', path: '/EditStore/:StoreId/tab/:tab', component: EditStore }
];
I am also using:
watch: {
// call again the method if the route changes
'$route': 'LoadStore'
},
to reload my component data when the url changes, but still nothing. I'm not sure what I'm doing wrong. I'm getting the same results in IE 11 and Chrome.
First of all your URL look kinda weird to me bcoz it has index.html, at least it could have been something like:
http://server/stores/#/ViewStore/:StoreId
Anyhow, can you push programatically and see if you are getting expected result?
this.$router.push({ name: 'ViewStore', params: { StoreId: '1' } })

VUE route redirect not closing modal from other page

I am using vue2 routes set up by another dev but I am trying to change the 'redirect' currently set to go to the 'home' page.
This issue is that there is a page which when you first enter the page (for the very first time) a bootstrap modal is displayed. The issue I'm having is if I enter this page of the first time then change the URL, the 'redirect' is working as expected BUT the modal is also still displaying and I don't know how to make it close.
routes.js
import {store} from './store/store';
import Cart from './components/Cart';
import Stock from './components/Stock';
import Home from './components/Home.vue';
import Review from './components/Review';
import Order from './components/Order.vue';
import OrderReport from './components/OrderReport';
import AccountDetails from './components/AccountDetails';
import ExistingOrders from './components/ExistingOrders';
export const routes = [
{path: '', component: Home},
{path: '/order', component: Order},
{
path: '/review', component: Review, children: [
{path: '', component: ExistingOrders},
{
path: ':id', component: OrderReport, beforeEnter: (to, from, next) => {
let orderCount = store.getters.orderPaginator.items.filter(item => item.id === +to.params.id).length;
next(orderCount > 0);
}
}
]
},
{path: '/account', component: AccountDetails},
{path: '/stock', component: Stock},
{path: '/cart', component: Cart},
{path: '*', redirect: '/order'}
];
If I change "redirect: '/order'" to "redirect: '/'" it goes to my home page as expected but with the modal displayed. Is there a way to close on the redirect?
Page where modal should be displayed
**Changed URL to 'orders' and clicked 'Enter'
Directed to the correct page (Home page) but modal still displayed. Is there a way I can change the :key using routes or would I have to use something like this.$forceUpdate(), although I have read that this may not work in vue2 and is really a nice thing to do.
What's my best approach? Just to mention I am new to vue2
I had success with this approach.
You can use a feature called Global Before Guards in Vue Router.
Inside router folder index.js file:
const router = createRouter({
// not relevant to the answer
history: createWebHistory(process.env.BASE_URL),
routes
})
router.beforeEach((to, from, next) => {
// remove modal backdrop if one exists
let modalBackground = document.querySelector('.modal-backdrop')
if (modalBackground) {
modalBackground.remove()
}
// do other stuff
next()
})
In my case I wanted to remove the modal backdrop but you can modify this to suit your needs.
Probably not the cleanest or best way to resolve the issue but the only way I could think of was to use the following in my 'home.vue' file
mounted() {
this.closeAccountSelectModal();
},
methods: {
closeAccountSelectModal() {
$('.modal ').modal('hide');
}
}
Used the class so all other pages which have modals will also be covered by it.
I know its too late but you can watch for route changes in components so when the route changes just close the modal
watch:{
$route (to, from){
// hide modal
}
}

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.

Can i split up children routes into component files?

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,
}
]
});

Vue Router - beforeDestroy is called for parent component when children route changes

I have my routes defined like this
{
path: '/menu',
component: () => import('./Menu.vue'),
children: [
{
path: 'admin',
component: () => import('./menus-admin/MenusAdmin.vue'),
name: 'menusAdmin'
},
{
path: 'import',
component: () => import('./menus-admin/menus-import/MenusImport.vue'),
name: 'menusImport'
}
]
}
When I navigate between the admin and import routes using router-link components, the parent Menu.vue component gets destroyed and created again. I would expect the Menu.vue component to no bet destroyed unless I navigate to a completely different route. This is a problem because I have implemented some lifecycle hooks that I don't want to be called over and over when the child routes change.
Am I doing something wrong? Is this a bug or is it a feature?
I found my problem. My <router-view> had :key="$route.fullPath" on it. That was forcing it to re-render everything on every route change.
Removed that and it worked as expected.