blackcityhenry
blackcityhenry

Reputation: 727

Vue Router beforeEnter vs beforeEach

I am trying to redirect non-logged in user from all pages to /login. I tried beforeEach() but it doesn't fire when user enter site with direct url like /home, /event.

Per-Route Guard beforeEnter() works perfectly since it fires once the user lands on that particular page. However, it requires me to add beforeEnter() on every routes.

I am looking for a way to duplicate that beforeEnter() on almost every page on the router (even on dynamic pages) which non-logged in user will be redirected to /login.

This one works when user enter with direct url /home.

routes: [
  {
    path: '/home',
    name: 'home',
    beforeEnter(to, from, next){
      if ( to.name !== 'login' && !this.isloggedin ){
         next({
           path: 'login',
           replace: true
         })
      } else {
         next()
      }
    }
  },
  ...
]

This one only works after user entered the site and route changed

vm.$router.beforeEach((to, from, next)=>{
  if ( to.name !== 'login' && !this.isloggedin ){
    next({
      path: 'login',
      replace: true
    })
  } else {
    next();
  }
})

Thanks in advance.

Upvotes: 9

Views: 44870

Answers (2)

Ahmed El-Atab
Ahmed El-Atab

Reputation: 681

For a global and neat solution, you can control the router behavior in the App.vue using the router.beforeResolve(async (to, from, next) => {});.

beforeResolve is better than beforeEach, as beforeResolve will not load the component of the accessed path URL unless you fire manually the next function.

This is very helpful as you'll not render any interafce unless you check the authentication status of the user and then call next().

Example:

   router.beforeResolve(async (to, from, next) => {
  // Check if the user is authenticated.
  let isUserAuthenticated = await apiRequestCustomFunction();

  // Redirect user to the login page if not authenticated.
  if (!isUserAuthenticated) {
    location.replace("https://example.com/signin");
    return false;
  }
  
  // When next() is called, the router will load the component corresponding
  // to the URL path.
  next();
});

TIP: You can display a loader while you check if the user is authenticated or not and then take an action (redirect to sign in page or load the app normally).

Upvotes: 0

Dan
Dan

Reputation: 63069

It looks like this beforeEach is being defined inside an initialized component, which means the first routing has already occured. Define it in the router module with your routes instead:

const router = new VueRouter({
...
})

router.beforeEach((to, from, next)=>{
  if ( to.name !== 'login' && !this.isloggedin ){
    next({
      path: 'login',
      replace: true
    })
  } else {
    next();
  }
})

Hopefully you are using Vuex and can import the store for store.state.isloggedin. If not using Vuex yet, this illustrates why it is useful for global state.

Upvotes: 9

Related Questions