Home > Software design >  Conditionally show view using Vue Router
Conditionally show view using Vue Router

Time:11-29

So I'm trying to achieve a layout with optional sidebars based on the vue routes

Currently I have the following:

  1. an App.vue which has a MainLayout component with slots where I'm placing the router views
<main-layout>
    <template #main>
        <router-view/>
    </template>
    <template #sidebar>
        <router-view name="LeftSidebar"/>
    </template>
    <template #rightsidebar>
        <router-view name="RightSidebar"/>
    </template>
</main-layout>
  1. the router looking something like this:
const routes = [
  {
    path: "/lectures",
    components: {
      default: LectureList,
      LeftSidebar: MainMenu,
    }
  },
  {
    path: "/users",
    components: {
      default: UserList,
      LeftSidebar: MainMenu,
      RightSidebar: SomeOtherComponent
    }
  },
]
  1. the MainLayout.vue looking something like this (simplified)
<div>
    <div >
        <slot name="sidebar"/>
    </div>
    <div >
        <slot/>
    </div>
    <div >
        <slot name="rightsidebar"/>
    </div>
</div>

Currently the main menu layout has a slot for the rightsidebar and I'd like it to render only if it has some content, ie if some route provides a component for the RightSidebar router view. I tried looking at the slots in MainLayout and add a v-if on the .right-sidebar div to only show if the slot for rightsidebar slot is present, but I guess it doesn't work since the router-view is present in there already

Any recommended way of dealing with this type of case?

CodePudding user response:

Using the matched property of the Vue router named views, we can check which props have been passed or not.

Here in the code, I added a watcher which will check for every route if props for sidebar views are passed or not and will update the data properties to used as the conditions.

<main-layout>
   <template #main>
      <router-view/>
   </template>
   <template #sidebar v-if="isLeftSideBar">
      <router-view name="LeftSidebar"/>
   </template>
   <template #rightsidebar v-if="isRightSideBar">
      <router-view name="RightSidebar"/>
   </template>
</main-layout>

<script >
export default {
    name: "App",
    data() {
        return {
            isLeftSideBar: false,
            isRightSideBar: false
        }
    },
    watch: {
        $route(to, from) {
            if (to.matched.length) {
                this.isLeftSideBar = to.matched[0].props.hasOwnProperty("LeftSidebar");
                this.isRightSideBar = to.matched[0].props.hasOwnProperty("RightSidebar");;
            }
        }
    },
} 
      
</script>

Please let me know if this works.

  • Related