skip to Main Content

I am using Vue2 and vue router 3x. How can I execute a store action whenever a specific child route is hit regardless if it is hit through a button press or the browser back/forward buttons?

I need to fire off an API call whenever a specific child route is hit. Currently the code works fine, however, the second a user presses the browsers back/forward buttons it breaks.

Here is a breakdown of the problem…

The way my router is setup is like:

const router = new Router({
  mode: 'history',
  routes: [
    {
      path: '/browse/food/:foodId',
      name: 'Food',
      component: foodComp,,
      children: [
        {
          path: ':routeTitle',
          name: 'FoodDescription',
          component: foodDescriptionComp,
          props: {
            viewMode: 'TEXT',
          },
        },
        {
          path: ':routeTitle',
          name: 'FoodImage',
          component: foodDescriptionComp,
          props: {
            viewMode: 'IMAGE',
          },
        },
        {
          path: ':routeTitle/food-translation',
          name: 'FoodTranslation',
          component: foodTranslationComp,
        },
      ],
    },
    ...lotsOfOtherRoutes,
  ],
});

…the foodDescriptionComp has pagination built into it to flip between different foods, that is trigger on click of the "next page" (or page number) button, and that method is setup like this:

methods: {
  switchPage(pageNumber, foodIdForPageSelection) {
    this.$router.push({
      name: 'FoodDescription',
      params: { foodId: foodIdForPageSelection },
    });

    await this.loadFoodByPage({
      catalogId: this.catalogId,
      pageNumber,
    });
  }
}

As you can see the page router will update the route and then as a separate action I call loadFoodByPage. As mentioned above, this works great, but if a user tries to use their browsers back button instead then the loadFoodByPage will never be called.

I have tried a few things to solve this:

I have tried adding beforeEnter and moving the loadFoodByPage to the beforeEnter, however, that is only hit on the initial page load.

I believe using beforeEach would work but we have hundreds of routes in our application and it seems silly to add logic for this one specific child route that will be checked on every single page.

I’ve tried getting really hacky, but this solution below does not work as it only maintains the history one press back – so for example if I go from the login page then redirect to the food 1, then go to 2, 3, 4 and I press the back button in the browser it will go back and load page 3, then I press back again and it goes to the login page. Even if this approach did work, it feels extremely anti-pattern.

// Back/Forward browser button pressed
window.onpopstate = function () {
  window.location.reload();
};

2

Answers


  1. I think you could add a watch on this.$route.name, and then based on route name, call your API

    Login or Signup to reply.
  2. Untested but this should work in principle. The idea being this will be triggered per route change, with the page number being set in the URL. If there is no page number in the URL then 1 is used.

    methods: {
      switchPage(pageNumber, foodIdForPageSelection) {
        this.$router.push({
          name: 'FoodDescription',
          params: { foodId: foodIdForPageSelection },
          query: { pageNumber }
        })
    },
    watch:{
      '$route' (to, from){
        if(to.name === 'FoodDescription') {
          this.loadFoodByPage({
            catalogId: this.catalogId,
            pageNumber: this.pageNumber ? this.pageNumber : 1,
        });
        }
      }
    },
    computed: {
      pageNumber: () => {
          return this.$route.query.pageNumber;
        }
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search