title: Vue router - how to have multiple components loaded on the same route path based on user role?
body: <p>I have app where user can login in different roles, eg. <code>seller</code>, <code>buyer</code> and <code>admin</code>.
  For each user I'd like to show dashboard page on the same path, eg. <code>http://localhost:8080/dashboard</code>
  However, each user will have different dashboard defined in different vue components, eg. <code>SellerDashboard</code>, <code>BuyerDashboard</code> and <code>AdminDashboard</code>.</p>
  
  <p>So basically, when user opens <code>http://localhost:8080/dashboard</code> vue app should load different component based on the user role (which I store in vuex). Similarly, I'd like to have this for other routes. For example, when user goes to profile page <code>http://localhost:8080/profile</code> app should show different profile component depending on the logged in user.</p>
  
  <p>So I'd like to have the same route for all users roles as opposed to have different route for each user role, eg. I don't want user role to be contained in url like following: <code>http://localhost:8080/admin/profile</code> and <code>http://localhost:8080/seller/profile</code> etc...</p>
  
  <p>How can I implement this scenario with vue router?</p>
  
  <p>I tried using combination of children routes and per-route guard <code>beforeEnter</code> to resolve to a route based on user role. Here is a code sample of that:</p>
  
  <p>in <strong>router.js</strong>:</p>
  
  <pre class="lang-js prettyprint-override"><code>import Vue from 'vue'
  import VueRouter from 'vue-router'
  import Home from '../views/Home.vue'
  import store from '@/store'
  
  Vue.use(VueRouter)
  
  const routes = [
    {
      path: '/',
      name: 'home',
      component: Home,
  
      beforeEnter: (to, from, next) =&gt; {
        next({ name: store.state.userRole })
      },
  
      children: [
        {
          path: '',
          name: 'admin',
          component: () =&gt; import('@/components/Admin/AdminDashboard')
        },
        {
          path: '',
          name: 'seller',
          component: () =&gt; import('@/components/Seller/SellerDashboard')
        },
        {
          path: '',
          name: 'buyer',
          component: () =&gt; import('@/components/Buyer/BuyerDashboard')
        }
      ]
    },
  ]
  
  const router = new VueRouter({
    mode: 'history',
    base: process.env.BASE_URL,
    routes
  })
  
  export default router
  </code></pre>
  
  <p>in <strong>store.js</strong>:</p>
  
  <pre class="lang-js prettyprint-override"><code>import Vue from 'vue'
  import Vuex from 'vuex'
  
  Vue.use(Vuex)
  
  export default new Vuex.Store({
    state: {
      userRole: 'seller' // can also be 'buyer' or 'admin'
    }
  })
  </code></pre>
  
  <p><strong>App.vue</strong> contains parent router-view for top-level routes, eg. map <code>/</code> to <code>Home</code> component and <code>/about</code> to <code>About</code> component:</p>
  
  <pre class="lang-js prettyprint-override"><code>&lt;template&gt;
    &lt;router-view/&gt;
  &lt;/template&gt;
  
  &lt;script&gt;
  export default {
    name: 'App',
  }
  &lt;/script&gt;
  </code></pre>
  
  <p>And <strong>Home.vue</strong> contains nested <code>router-view</code> for different user's role-based components:</p>
  
  <pre class="lang-js prettyprint-override"><code>&lt;template&gt;
    &lt;div class="home fill-height" style="background: #ddd;"&gt;
      &lt;h1&gt;Home.vue&lt;/h1&gt;
      &lt;!-- nested router-view where user specific component should be rendered --&gt;
      &lt;router-view style="background: #eee" /&gt;
    &lt;/div&gt;
  &lt;/template&gt;
  
  &lt;script&gt;
  export default {
    name: 'home'
  }
  &lt;/script&gt;
  </code></pre>
  
  <p>But it doesn't work because I get <code>Maximum call stack size exceeded</code> exception in browser console when I call <code>next({ name: store.state.userRole })</code> in <code>beforeEnter</code>. The exception is:</p>
  
  <pre><code>vue-router.esm.js?8c4f:2079 RangeError: Maximum call stack size exceeded
      at VueRouter.match (vue-router.esm.js?8c4f:2689)
      at HTML5History.transitionTo (vue-router.esm.js?8c4f:2033)
      at HTML5History.push (vue-router.esm.js?8c4f:2365)
      at eval (vue-router.esm.js?8c4f:2135)
      at beforeEnter (index.js?a18c:41)
      at iterator (vue-router.esm.js?8c4f:2120)
      at step (vue-router.esm.js?8c4f:1846)
      at runQueue (vue-router.esm.js?8c4f:1854)
      at HTML5History.confirmTransition (vue-router.esm.js?8c4f:2147)
      at HTML5History.transitionTo (vue-router.esm.js?8c4f:2034)
  </code></pre>
  
  <p>and thus nothing is rendered.</p>
  
  <p>Is there a way I can solve this?</p>