3
votes

I was wondering if its possible to define custom properties when passing routes to VueRouter. For example for the majority of routes in my app I would like to define a route such as the following where I can pass a component to an optional property "menu":

{ path: "/section-stack", component: SectionStack, menu: SectionMenu }

A read of the docs points towards using the meta field for this but this doesn't achieve what I want and results in more verbose routes. Looking into the code, each route passed to VueRouter is of type RouteConfig. Is it possible to modify my VueRouter so that it can be passed routes of a different type? I.e. of type RouteConfig with additional properties.

2

2 Answers

7
votes

I think meta is still the way to go. I once created a breadcrumb with it. My route looked like this:

  routes: [
    {
      path: '/',
      name: 'home',
      component: require('./routes/Home.vue'),
      meta: {
        history: [],
      },
    },
    {
      path: '/projects',
      name: 'projects',
      component: () => System.import('./routes/Projects.vue'),
      meta: {
        history: ['home'],
      },
    },
    {
      path: '/project/:token',
      name: 'project',
      component: () => System.import('./routes/project/Overview.vue'),
      meta: {
        text: (vue) => vue.projects[vue.$route.params.token] || vue.$route.params.token,
        to: { name: 'project', params: { token: (vue) => vue.$route.params.token } } ,
        history: ['home', 'projects'],
    }
  ]

In my vue-component I could access the meta by watching $route and while loading the component by iterating through the $router object like this:

export default {
    beforeMount() {
      this.allRoutes = {};
      this.$router.options.routes.forEach(route => {
          if (route.name) {
            let text = (route.meta && route.meta.text) || route.name;
            this.$set(this.allRoutes, route.name, {
                text: text,
                to: (route.meta && route.meta.to) || { name: route.name }
              }
            );
          }
        }
      );
    },
    data() {
      return {
        allRoutes: {},
        currentList: [],
      };
    },
    watch: {
      '$route'(to, from) {
        this.currentList = ((to.meta && to.meta.history).slice(0) || []);
        this.currentList.push(to.name);
      }
    },
  }

Especially the forEach in beforeMount could be a solution to build a menu, that f.e. is based on roles that are defined in the meta-object.

0
votes

To complement my comment in the first answer (formatting not supported in comments) and build off of Markus Madeja's answer, if you want the meta property to be type-safe, you could define your own custom type extending RouteConfig:

import { RouteConfig } from 'vue-router'
...
export type MyAppRouteConfig = Omit<RouteConfig, 'meta'> & {
  meta: {
    property1: string,
    property2: number,
    ...
  }
}