VUE route redirect not closing modal from other page - vuejs2

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
}
}

Related

Vue route with dynamic import causes default layout to flash for split of second

I'm using Vue 3 with vue-router and vite-plugin-pages, which by default loads all route components asynchronously.
I have made a simple layout component which switches between LayoutDefault and LayoutBlank, based on the route's meta. Blank is only for public sites like the login page, where user is not yet logged in. I made it this way so I only need to set the layout on few routes instead of all of them.
Because of the dynamic import though, when entering the site and being redirected to the login site via router's beforeEach guard, you can see the default layout being drawn for a split of a second and then switches to blank layout. This happens, because route.meta.layout in the watcher is always undefined at the beginning.
I could make /login to load synchronously, but I don't like this approach as I might be adding more "public" routes that should render in LayoutBlank, and same glitch also happens on them even when entering directly and not being redirected by the router.
Is there any fix to this other than switching the order of layouts so blank is default or loading everything synchronously? I tried to use another beforeEach hook instead of watching route.meta.layout but all it did, was moving the glitch to route leaving instead of entering when layouts were switched.
I couldn't use Vue3 in snippet so I put a simple demo code here:
https://stackblitz.com/edit/vue3-vue-router-meta-layout-spc5tq?file=src%2Flayouts%2FAppLayout.vue,src%2Frouter.ts
When you reload the web container, you will notice the red "Default Layout" text flicker.
Some code:
<script setup lang="ts">
import AppLayoutDefault from './AppLayoutDefault.vue'
import AppLayoutBlank from './AppLayoutBlank.vue'
import { markRaw, ref, watch } from 'vue'
import { useRoute } from 'vue-router'
const layout = ref()
const route = useRoute()
watch(
() => route.meta?.layout as string | undefined,
(metaLayout) => {
layout.value = markRaw(metaLayout === 'blank' ? AppLayoutBlank : AppLayoutDefault)
},
{ immediate: true }
)
</script>
<template>
<component :is="layout"> <router-view /> </component>
</template>
import { createRouter, createWebHistory } from 'vue-router'
import Home from '#/views/Home.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
component: Home,
},
{
path: '/login',
component: () => import('#/views/Login.vue'),
meta: { layout: 'blank', public: true },
},
{
path: '/admin',
component: () => import('#/views/Admin.vue'),
meta: { layout: 'AppLayoutAdmin' },
},
],
})
let isLoggedIn = false
router.beforeEach((to) => {
if (!to.meta.public && !isLoggedIn) {
isLoggedIn = true
return 'login'
}
})
export default router
I have actually found an answer! It was caused by most examples on the internet not ever mentioning router.isReady()! I was curious why route.fullPath returned / on every page load, even when entering /login. This led me to this snippet:
router.isReady().then(() => app.mount())
And guess what, delaying app.mount() like that actually fixed my whole problem. Now the first layout that is rendered is actually the one configured in the route, even if it's not the default one.

How do I router-link to the same page with an updated query & reload the page? [duplicate]

As part of my Quasar app, I have the following route:
import { RouteRecordRaw} from 'vue-router'
import { uid } from 'quasar'
const routes: RouteRecordRaw[] = [
{
path: '/',
redirect: () => {
console.log('matched /')
return {path: `/${uid()}`}
}
},
{
path: '/:uuid',
component: () => import('pages/User.vue')
// component: User,
},
];
export default routes;
This works fine when going to /: the URL is changed to /73a219e5-2cf2-4dd0-8... and User.vue is executed (specifically there a fetch inside that retrieves some data based on the :uuid parameter.
If I force a route from within a component (User.vue for instance), via
import { useRouter } from 'vue-router'
const router = useRouter()
router.push('/')
I do see that the URL changes to a new UUID but User.vue is not executed. Specifically, a reference to route.params.uuid where const route = useRoute() is not reactive.
Is this normal (= I have to look for anther way to trigger), or is there a misuse (erroneous use) on my side?
The core of the issue is that you're (re)using the same component for rendering the page you're navigating from and the page you're navigating to.
By design, Vue optimises DOM rendering and will reuse the existing component instance. This means certain hooks won't be triggered (e.g: mounted, created, etc...) when changing route.
To force Vue into creating a different component instance when the route changes, use the current route's .fullPath as key on <router-view>:
<template>
...
<router-view :key="route.fullPath"></router-view>
...
</template>
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute();
</script>

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.

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 router hot reload not working when lazy loading in router in a typescript project

I'm new to vue and building my first app. I was following a tutorial and noticed a way to lazy load in the router:
import Vue from 'vue'
import Router from 'vue-router'
import MainContent from '#/layout/main-content.vue'
import Home from '#/views/home.vue'
Vue.use(Router)
export default new Router({
mode: 'history',
routes: [
{
path: '/',
component: MainContent,
children: [
{
path: ''
//This works
component: Home
//This doesn't work
component: () => import('#/views/home.vue')
},
{
path: 'home'
//This works
component: Home
//This doesn't work
component: () => import('#/views/home.vue')
}
]
}
]
})
You can see in the above example, I'm showing the synchronous way and the asynchronous way. There are two paths to the home component because I need to be able to support the root '/' and the '/home' as the default. That's not the issue because it works the synchronous way (plus, I tried it with other child routes).
The strange thing is when I lazy load, the page doesn't refresh (hot load) until I inspect using the browser tool. Even when I force a refresh in the browser, it doesn't appear. When I open the inspector, then I see the home component in the browser. Why would I only see the Home component when I open the inspector?