On my vuejs application there is a dashboard, where the user can click a button that send him to /room (router.push("/room");).
When the user arrive on the page, the "mounted" function is triggered and a simple console.log is emited. That works.
mounted() {
console.log("room mounted");
}
If the user press the "back" button of his browser and go back to the dashboard, he can click the button again to join the room, except this time, the "mounted" function is not triggered.
Is there a way to make this works ?
Thank you.
In response to a part of your response to the answer below,
what I'm looking for is when I click again on the button that trigger
the router.push("/room"), because when I'm redirected, mounted nor
updated` are called.
To solve your problem, you can watch the $route object, by doing
watch: {
'$route' () {
// this will be called any time the route changes
}
},
This is expected behavior in Vue Router according to this issue on the Vue Router GitHub repo:
This is expected behaviour, Vue re-uses components where possible.
You can use the beforeRouteUpdatehook to react to a route switch that
uses the same component.
Navigating "back" to an already-mounted component won't trigger a subsequent mounting of the component. To see which lifecycle hooks are triggered on Route Update, you can look at this blog post (scroll down to the Lifecycle Hooks diagram).
The situation you're running into is the "Client Update" column, where mounted is not called, but update is. In general, I tend to utilize parallel code in both beforeRouteEnter and beforeRouteUpdate. Sadly, it's a bit repetitive.
Related
It's basically a simple task: I'm using Vue3 with the Vue Router, there's my Home.vue component which lives in the / route, then there's a ProductDetails.vue component which lives in the /product route.
I want to execute a certain action when the user is navigating to my / route. However, I only want this action to happen when the user directly navigates here, meaning via clicking a link or via the browser's URL bar. I don't want the action to execute when he is navigating back from ProductsDetails.vue (or routing via "back" from anywhere, for that matter).
How do I achieve this with Vue3 or Vue Router methods? I know I can probably do it with query parameters in my URL but I'd prefer not to.
You could use in-component navigation guards (read more about it here (options api) OR here (composition api))
Your code could look something like this
...
beforeRouteEnter(to, from, next) {
if(from.path === '/') {
// do something
}
},
...
I have a vue.js application and I'd like to see the navigation history in vue-router. I have a beforeRouteLeave hook in my component and I put a breakpoint in there. It hits the breakpoint, and I type this.$router in the console. It outputs the $router object but I don't see an actual stack of urls representing the history of my navigation through the site.
This is what I see:
currentRoute: (...)
app: Vue {_uid: 3, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: Vue, …}
apps: [Vue]
options: {mode: "history", linkActiveClass: "active", routes: Array(47), scrollBehavior: ƒ}
beforeHooks: []
resolveHooks: []
afterHooks: [ƒ]
matcher: {match: ƒ, addRoutes: ƒ}
fallback: false
mode: "history"
history: HTML5History {router: VueRouter, base: "", current: {…}, pending: {…}, ready: true, …}
__proto__: Object
(I could expand this but I think that would be too big.)
Where is the actual navigation stack?
If you want to know why I need to see the navigation stack, it's because, when I click the back button on the browser, I suspect that the navigation stack is being popped even though my beforeRouteLeave hook is called and I don't call next(). I bring up a popup in beforeRouteLeave with the options: "leave" or "stay". If the user clicks "stay", I stay on the page. It seems to do the trick (it doesn't navigate away from the current page), but then if I click refresh on the browser, it refreshes with the previous page. Or if I say "stay" once, then click the back button again and say "leave", I go two pages back.
So I want to see what's going on with the navigation stack. Is it being popped regardless of whether next() is called in beforeRouteLeave, at least when I click the back button? Or is something else going on.
Thanks.
It's not currently implemented, though you can use router navigation guards (route change hooks) as a middleware to store the from and to argument objects and write your logic with these values.
Just make sure you call the next() function, otherwise you'll be storing logs and not calling the next route.
Check the docs here: https://router.vuejs.org/guide/advanced/navigation-guards.html
This doesn't directly answer your question about how to see the navigation history in vue-router, but I came across your question with a similar problem that you mentioned as well:
When I click the back button on the browser, I suspect that the navigation stack is being popped even though my beforeRouteLeave hook is called and I don't call next()
It seems the solution to this problem is to explicitly call next(false) according to the official vue-router documentation.
https://router.vuejs.org/guide/advanced/navigation-guards.html#global-before-guards
next(false): abort the current navigation. If the browser URL was changed (either manually by the user or via back button), it will be reset to that of the from route.
I've tested on vue 2.x and it solves the problem for me in cases where it was navigating to another route: e.g. /a -> /b but not in cases where it's navigating to the same route different param: e.g. /page/1 -> /page/2
I'm building a vue.js application. We'd like to have a popup come up when the user attempts to leave a specific page. The popup should say "Are you sure you want to leave the page?" I know I can implement something in the beforeRouteLeave hook of the component, but I'm wondering if there's a way to implement this in the beforeEach event of the router (i.e. not the component). The reason I'd like to use the router is because beforeEach in the router seems to respond to the user entering a different path in the browser url bar, whereas the beforeRouteLeave hook on the component does not. However, I don't have access to the popup in the router whereas I do in the component (the popup would just be part of the template).
So the question is: how can I bring up a popup in the router before the user actually leaves the page?
Thanks.
First you can assign a name for each of your routes objects in routes array inside your router or another field like requiredConfirmation or something like that, imagine that we have a routes like this :
routes : [
{
path : '/needconfirm',
component : NeedConfirmToLeaveCom,
name : 'needconfirm-route1'
},
{
path : '/neednotconfirm',
component : NeedNotConfirmToLeaveCom,
name : 'normal-route1'
},
]
then you can use router.beforeEach to set some conditions or some confirmations based on your Origin route and Destination route.
something like this :
router.beforeEach((to,from,next) => {
if(from.name.startsWith("needconfirm-")) {
if(window.confirm("Are you sure you want to leave the page?")) {
next();
}
}else next();
});
UPDATE * :
if you want to use some custom components for your popup, you can use vuex to store your component's logic and toggler and import that component in your App.Vue or other root/child components you wish. because you have access to your store management using $store right?
UPDATE ** :
and one other thing i want to mention, if you want to save some progress or state and because of that you want to get confirmation from user (progress will lost if they switch route), you should consider using Vuex to store your progress or state of your application and if you want more persisted solution you can use VuexPersisted store management which uses LocalStorage.
Vue router navigation guards document
Vuex Doc
You should use beforeunload event listener on the main component in that view.
MDN Reference
Depending on the browser, it will show the popup with default values populated.
This is how I use it in the created hook of the main component
window.addEventListener("beforeunload", (e) => {
e.preventDefault()
// chrome requires returnValue to be set
const message = "You have unsaved changes. Are you sure you wish to leave?"
e.returnValue = message
return message
})
I cant't figure out why the router-view does not emit the "login" event.
Here's the fiddle I'm playing with: https://jsfiddle.net/cvtwxf6h/22/
I want 2 different layouts, one for logged user and another for not logged user. The layout to display is determined by the logged property of the Index component.
When I click "Login" in the login page, a "login" event should propagate up to the Index component to update the logged property and change layout. For some reason the router-view does not emit the event, what am I doing wrong?
(I just want to understand the problem, I'm not interested in alternative ways to achieve this)
The problem seems to be the router-link navigates to a different route (via to="{name: 'index'}") before the login event is emitted, which causes the event to be lost somehow. If the target route is the same as the current route (no navigation), the event reaches the parent component without a problem.
A workaround would be to imperatively navigate with $router.push() after emitting the event:
const LoginPage = {
template: `<router-link to="" #click.native="switchToLoggedPage({ name: 'index' })">Login</router-link>`,
methods: {
switchToLoggedPage(route) {
this.$emit('login');
this.$router.push(route);
},
},
};
demo
Vue.js has mounted, created, updated etc. as states I can execute functions on the first load of the page - however how I execute for example a console.log('hi'); whenever the user navigates to a particular page/route without reloading the whole app?
Vue router exposes lifecycle hooks where you can execute you code: docs
beforeEach is the way to go if you need to execute a code upon every route navigation.
Alternatively, you can watch a current route inside your main (wrapper) component and execute code inside a watcher: docs, section Reacting to Params Changes
watch: {
'$route' (to, from) {
// react to route changes...
}
}