Editing routes in beforeEach fails because callback passes in invalid routes as to and from parameters

Viewed 43

I'm working on a mobile frontend with Vue. I'd like to dynamically change route transitions to slide left or right depending on the current tab index.

I set up a transition component in my App.js which switches the transition based off the route like this:

<transition :name="$route.meta.transition" mode="out-in">

So, to achieve what I want, I thought I could set up a beforeEach hook on each route change, and then modify the current route.meta.transition, and the .meta.transition of the route I'm navigating to.

Here are the route definitions:

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/routines',
      name: 'routines',
      component: () => import('../views/Routines/IndexView.vue'),
      meta: { transition: 'slide-right', index: 0 }
    },
    {
      path: '/routines/create',
      name: '/routines/create',
      component: () => import('../views/Routines/CreateView.vue'),
      meta: { transition: 'zoom-in', index: 0 }
    },
    {
      path: '/routines/:id',
      name: '/routines/id',
      component: () => import('../views/Routines/RoutineView.vue'),
      meta: { transition: 'zoom-in', index: 0 }
    },
    {
      path: '/log',
      name: 'log',
      component: () => import('../views/LogView.vue'),
      meta: { transition: 'slide-right', index: 1 }
    },
    {
      path: '/progress',
      name: 'progress',
      component: () => import('../views/ProgressView.vue'),
      meta: { transition: 'slide-right', index: 2 }
    },
    {
      path: '/settings',
      name: 'settings',
      component: () => import('../views/SettingsView.vue'),
      meta: { transition: 'slide-right', index: 3 }
    }
  ]
})

And this is the hook I'm setting up to replace the to and from routes with modified routes with the appropriate string:

router.beforeEach((to, from, next) => {
  console.log(to, from)
  if (to.meta.index < from.meta.index) {
    console.log({...to, meta: {...to.meta, transition: 'slide-left'}})
    router.addRoute({...to, meta: {...to.meta, transition: 'slide-left'}})
    console.log({...from, meta: {...from.meta, transition: 'slide-left'}})
    router.addRoute({...from, meta: {...from.meta, transition: 'slide-left'}})
  }
  next()
})

However, it appears that the to and from parameters don't have the component keys I defined earlier, so when I replace the routes with addRoute by navigating away and then navigate back, I get this error: Error: Invalid route component

Confirmation that the to and from objects are invalid routes:

enter image description here

How can I solve this issue to achieve a dynamic sliding behavior? I think this hook strategy makes sense. In the future, I'd like to add some more logic to let my child pages zoom in and out when you navigate between a parent and child page.

Thanks!

1 Answers

Instead of using router.addRoute(), you can update the route meta directly from the router hook. The Vue Router docs suggest using the afterEach() hook:

// router.js
router.afterEach((to, from) => {
  to.meta.transition = to.meta.index < from.meta.index ? 'slide-right' : 'slide-left'
})

demo

Related