learningMonk
learningMonk

Reputation: 1391

multiple different nested routes in same component based on conditional switch case - vue

I am implementing a players module. In here , there are 3 routing cards in initial page. Each card is routing to next page which is having multiple routing cards of their respective parent card.

Example

  1.  1st level Card( Player Name) -- > 2nd level Cards(Players info, Player Statistics, Records) --> upto 3rd level routing

  2.  1st level Card(Grounds) -- > 2nd level Cards(Grounds info, Match played, Records) --> upto 3rd level routing

  3.  1st level Card(Match Information) -- > 2nd level Cards(Match info, match history, community resources) --> upto 3rd level routing

Now, i have created that many components with respective routes. But, i want to create one component to route all different routes based on condition( $route.path)

Now, here is my routes.js

{
    name: 'Players',
    path: '/players',
    component: PageLayout,
    meta: {
        topNavigation: true
    },
    redirect: { path: '/players/entry' },
    children: [
        {
            name: 'PlayersEntryPage',
            path: 'entry',
            component: PlayersEntryPage
        },
        {
            name: 'PlayersName',
            path: 'name',
            component: PlayersName
        },
        {
            name: 'Grounds',
            path: 'grounds',
            component: Grounds
        },
        {
            name: 'MatchInformation',
            path: 'info',
            component: MatchInformation

        }
    ]
}

Here is the first home page and then 1st level subsequent card components for routing

PlayersEntryPage

    <template>
    <vu-page background="gray">
        <vu-container>
            <vu-row-control class="mt-3">
                 <vu-box-control :list="cardLists" @click="cardAction"></vu-box-control>
            </vu-row-control>
        </vu-container>
    </vu-page>
</template>

<script>
export default {
    data() {
        return {
            cardLists: [
                { heading: ‘PlName', content:’Players Name and information',to:'/players/name'},
                { heading: ‘Grnd',  content:  ‘Ground Information', to:'/players/grounds' },
                { heading: ‘Infos', content:  ‘Match Informations', to:'/players/info' }
            ]
        };
    },
    methods: {
        cardAction(value) {
            if(value) {
                this.$router.push(value.to);
            }
        }
    }
};
</script>

1st level component (PlayersName) -> 2nd level component cards

    <template>
    <vu-page background="gray">
        <vu-container>
            <vu-row-control class="mt-3">
                 <vu-box-control :list="cardLists" @click="cardAction"></vu-box-control>
            </vu-row-control>
        </vu-container>
    </vu-page>
</template>

<script>
export default {
    data() {
        return {
            cardLists: [
                { heading: ‘Players Personal Info', to:’/players/name/pinfo'},
                { heading: ‘Players Statistics', to:'/players/name/statistics' },
                { heading: ‘Players Records',to:’/players/name/records' }
            ]
        };
    },
    methods: {
        cardAction(value) {
            if(value) {
                this.$router.push(value.to);
            }
        }
    }
};
</script>

Box-control code snippet

    <template>
    <div class="box-wrapper">
        <div v-for="(items, i) in boxes" :key="'box-row-' + i" class="box-container">
            <vu-button-control
                v-for="item in items"
                :key="item.heading"
                plain
                class="box"
                :to="item.to"
                @click="click($event, item)"
            >
                <vu-row-control>
 <vu-column-control  cols="10">
                        <h1 class="label">{{ item.heading }}</h1>
                        <p class="body_content">{{ item.content }}</p>
                    </vu-column-control>

                    <vu-column-control cols="2">
                        <vu-button-control @click.stop=“addFavouriteClick(item)">
                        </vu-button-control>
                    </vu-column-control>
                </vu-row-control>
            </vu-button-control>
        </div>
    </div>
</template>

All other routing cards are following exactly same structure just one difference is the passed data. So, that's why i want one single component and based on $route path i want to change the data part.

I am thinking to use switch case approach but not able to do that conditional routing part.

Upvotes: 0

Views: 879

Answers (1)

muka.gergely
muka.gergely

Reputation: 8329

Sorry, but I'm not sure I understood your problem fully - but I try to give a solution to what I understood:

  • you have three levels of routing
  • you have different components for all the routes
  • you'd like to have 1 component for handling the routes

To achieve that I'd extend the router to pass subroutes props to a general component:

const PlayersInfo = {
  template: `
    <div>Players info component</div>
  `
}

const PlayerStatistics = {
  template: `
    <div>Player statistics component</div>
  `
}

const PlayerRecords = {
  template: `
    <div>Player records component</div>
  `
}

const GroundsInfo = {
  template: `
    <div>Grounds info component</div>
  `
}

const MatchPlayed = {
  template: `
    <div>Match played component</div>
  `
}

const GroundsRecords = {
  template: `
    <div>Grounds records component</div>
  `
}

const MatchInfo = {
  template: `
    <div>Match info component</div>
  `
}

const MatchHistory = {
  template: `
    <div>Match history component</div>
  `
}

const CommunityResources = {
  template: `
    <div>Community resources component</div>
  `
}

// RoutingControl can be called inside itself
const RoutingControl = {
  props: ["subroutes"],
  template: `
    <div>
      <router-link
        v-for="subroute in subroutes"
        :key="subroute"
        :to="{ name: subroute }"
        class="link"
      >
        {{ subroute }}
      </router-link><br />
      <router-view />
    </div>
  `
}

const routes = [{
    name: 'Root',
    path: '/',
    redirect: {
      path: '/players/entry',
    },
  },
  {
    name: 'Players',
    path: '/players',
    component: RoutingControl,
    meta: {
      topNavigation: true
    },
    redirect: {
      path: '/players/entry'
    },
    props: (route) => ({
      subroutes: getRouteNames("Players")
    }),
    children: [{
      name: 'PlayersEntryPage',
      path: 'entry',
      component: RoutingControl,
      props: (route) => ({
        subroutes: getRouteNames("PlayersEntryPage"),
      }),
      children: [{
          name: 'PlayersName',
          path: 'name',
          component: RoutingControl,
          props: (route) => ({
            subroutes: getRouteNames("PlayersName"),
          }),
          children: [{
            name: 'Players info',
            path: 'players-info',
            component: PlayersInfo,
          }, {
            name: 'Player Statistics',
            path: 'player-statistics',
            component: PlayerStatistics,
          }, {
            name: 'Player records',
            path: 'player-records',
            component: PlayerRecords,
          }],
        },
        {
          name: 'Grounds',
          path: 'grounds',
          component: RoutingControl,
          props: (route) => ({
            subroutes: getRouteNames("Grounds"),
          }),
          children: [{
            name: 'Grounds info',
            path: 'grounds-info',
            component: GroundsInfo,
          }, {
            name: 'Match played',
            path: 'match-played',
            component: MatchPlayed,
          }, {
            name: 'Grounds records',
            path: 'grounds-records',
            component: GroundsRecords,
          }],
        },
        {
          name: 'MatchInformation',
          path: 'info',
          component: RoutingControl,
          props: (route) => ({
            subroutes: getRouteNames("MatchInformation"),
          }),
          children: [{
            name: 'Match info',
            path: 'match-info',
            component: MatchInfo,
          }, {
            name: 'match history',
            path: 'match-history',
            component: MatchHistory,
          }, {
            name: 'community resources',
            path: 'community-resources',
            component: CommunityResources,
          }],
        }
      ],
    }, ]
  }
]

// get subroutes automatically for router (by route name)
function getChildrenRoutesNames(arr) {
  return (routeName) => {
    let ret = []
    arr.forEach(route => {
      if (route.name === routeName) {
        ret = route?.children.map(({
          name
        }) => name)
      } else {
        if (route?.children?.length) {
          ret = [...ret, ...getChildrenRoutesNames(route.children)(routeName)]
        }
      }
    })
    return ret
  }
}

// "fixing" the routes array scope, so it stays when used
// inside that array
const getRouteNames = getChildrenRoutesNames(routes)

const router = new VueRouter({
  routes,
})

new Vue({
  el: "#app",
  router,
})
.link {
  padding: 0 8px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

<div id="app">
  <router-view />
</div>

I hope this is close to what you were looking for :)

Upvotes: 1

Related Questions