I've got the following code:
const routes = [
{ path: '/', ponent: FooView },
{ path: '/bar', ponent: BarView }
];
const router = new VueRouter({
routes
});
router.beforeEach(function(to, from, next) {
if (to.path === '/bar') {
next('/');
}
next();
});
If I've omitted too much and you need to see other pieces of code related to the router let me know so I can fill it in.
If I open up a new tab and navigate to '/#/bar' I'm successfully redirected to '/#'. However, if I then go into the address bar and manually add '/#/bar' and hit enter I am not redirected. If I then hit enter in the address bar again I am redirected.
I've stepped through the code in the console and I see that it is calling next('/')
and I see where it calls push('/')
inside of next('/')
but it doesn't take affect until I've hit enter in the address bar a second time.
I've tried using router.replace('/')
but the behaviour is the same. I've tried using beforeEnter
on the individual route but the behaviour is also the same.
Two links I've found where similar behaviour is discussed are: and but neither helped me.
Is someone able to explain this? Is there a disconnect between what I'm trying to do and what functionality vue-router provides? If this behaviour isn't expected can someone propose a work around?
I've got the following code:
const routes = [
{ path: '/', ponent: FooView },
{ path: '/bar', ponent: BarView }
];
const router = new VueRouter({
routes
});
router.beforeEach(function(to, from, next) {
if (to.path === '/bar') {
next('/');
}
next();
});
If I've omitted too much and you need to see other pieces of code related to the router let me know so I can fill it in.
If I open up a new tab and navigate to '/#/bar' I'm successfully redirected to '/#'. However, if I then go into the address bar and manually add '/#/bar' and hit enter I am not redirected. If I then hit enter in the address bar again I am redirected.
I've stepped through the code in the console and I see that it is calling next('/')
and I see where it calls push('/')
inside of next('/')
but it doesn't take affect until I've hit enter in the address bar a second time.
I've tried using router.replace('/')
but the behaviour is the same. I've tried using beforeEnter
on the individual route but the behaviour is also the same.
Two links I've found where similar behaviour is discussed are: https://github./vuejs/vue-router/issues/748 and https://forum.vuejs/t/router-beforeeach-if-manually-input-adress-in-browser-it-does-not-work/12461/2 but neither helped me.
Is someone able to explain this? Is there a disconnect between what I'm trying to do and what functionality vue-router provides? If this behaviour isn't expected can someone propose a work around?
Share Improve this question asked Apr 12, 2018 at 19:24 Billy MonkBilly Monk 5431 gold badge5 silver badges10 bronze badges 3-
You meant
router.beforeRouteEnter
and notrouter.beforeEach
in your example, right? – Brian Kung Commented Apr 12, 2018 at 23:31 -
Hey @BrianKung I meant
beforeEach
. Most documentation I've read has made reference tobeforeEach
being the guard to use for my use case. At least that is how I've interpreted what I've read. – Billy Monk Commented Apr 13, 2018 at 15:59 - I should also note that my use case has more than one route that needs this logic so a global guard like beforeEach is preferable. – Billy Monk Commented Apr 14, 2018 at 16:41
3 Answers
Reset to default 6In the vue-router official documentation, the way you implement the beforeEach() is not remended. Here is what the documentation says:
Make sure that the next function is called exactly once in any given pass through the navigation guard. It can appear more than once, but only if the logical paths have no overlap, otherwise the hook will never be resolved or produce errors. Here is an example of redirecting to user to /login if they are not authenticated:
// BAD
router.beforeEach((to, from, next) => {
if (!isAuthenticated) next('/login')
// if the user is not authenticated, `next` is called twice
next()
})
// GOOD
router.beforeEach((to, from, next) => {
if (!isAuthenticated) next('/login')
else next()
})
Not sure why the first one is a bad example, since both sample code should work exactly the same logically. My code pops error when the first time redirect the path using next('/'), however, the rerouting still success. Looking for answer from pros.
Without getting too excited (a lot of testing left to do) it appears as though I've managed to fix my issue.
Instead of:
router.beforeEach(function(to, from, next) {
if (to.path === '/bar') {
next('/');
}
next();
});
I changed the code to the following:
router.beforeEach(function(to, from, next) {
if (to.path === '/bar') {
next('/');
return;
}
next();
});
Note the added return;
in the if statement.
I still have questions about the behaviour. In particular I need too investigate deeper why sometimes it would hit the route when the only difference is whether it is the first or second time I entered the URL into the address bar. I'm sure diving deeper into next
will answer my question.
Anyway, adding the return;
turned this into a non blocker.
As other answers mention, the next()
function should be called exactly once inside the same guard.
It is important that it is called at least once or the guard will never plete and block the navigation.
As taken from the docs -->
Make sure that the next function is called exactly once in any given pass through the navigation guard. It can appear more than once, but only if the logical paths have no overlap, otherwise the hook will never be resolved or produce errors
The next()
function signals that this guard has finished and the next guard may be called.
By doing this it is possible to create asynchronous guards that only finish when the next() function is called.
However the rest of the code inside the guard is still executed.
This means that if you call next()
several times it will cause unpredictable behavior.
// This will work
if(condition){
next();
}
else{
next();
}
// This cause you pain!
next();
next();
The 'next' function also takes parameters:
// This aborts the current navigation and "stays" on the same route
next(false)
// These navigate to a different route than specified in the 'to' parameter
next('/');
next({path: '/'})
next({path: '/', query: {urlParam: 'value'}}) // or any option used in router.push -> https://router.vuejs/api/#router-forward
// If the argument passed to next is an instance of Error,
// the navigation will be aborted and the error
// will be passed to callbacks registered via router.onError().
next(new Error('message'))