0

Some of the components needs to be hidden for particular Routes. I was able to achieve that using watcher for route change found from this SO question - Vuejs: Event on route change. I don't want to show header and sidebar in customizePage ( route - /customize ). But there is a problem when I do a hard reload from that particular page. That doesn't execute the watch and hence the it fails. The solution I found was having it also in mounted(), so that it executes also on reload.

But having the same function in mounted and watcher looks weird. Is there a better way to do it ?

<template>
    <div>
        <TrialBanner v-if="$store.state.website.is_trial"/>
        <div class="page-body-wrapper" :class="{ 'p-0' : isCustomizePage}">
            <Sidebar :key="$store.state.user.is_admin" v-if="!isCustomizePage"/>
            <div class="main-panel" :class="{ 'm-0 w-100' : isCustomizePage}">
                <Header v-if="!isCustomizePage"/>
                <div class="content-wrapper" :class="{ 'p-0' : isCustomizePage}">
                    <router-view :key="$store.state.websiteId"></router-view>
                </div>
            </div>
        </div>
    </div>
</template>


mounted() {
  if(this.$route.path == '/customize') {
     this.isCustomizePage = true;
  } else {
     this.isCustomizePage = false;
  }
},
watch: {
  $route (to, from){
     if(this.$route.path == '/customize') {
       this.isCustomizePage = true;
     } else {
       this.isCustomizePage = false;
     }
  }
}
theFrontEndDev
  • 890
  • 1
  • 17
  • 41
  • You should consider using vue-router hooks instead of the watcher: https://router.vuejs.org/guide/advanced/navigation-guards.html#in-component-guards. Also, if you don't find any other solution, it would be cleaner to factorise the duplicated code into one single method :) – Kapcash Jul 16 '20 at 14:47

1 Answers1

2

Easy fix: Use an immediate watcher

watch: {
  $route: {
     immediate: true,
     handler(to, from) {
         if(this.$route.path == '/customize') {
           this.isCustomizePage = true;
         } else {
            this.isCustomizePage = false;
         }
     }
  }
}

More complex but more extensible fix: Use "layout" components.

Demo

General idea is to create "Layout" components, use the meta tag on routes to define the layouts for each route, and then use a dynamic component in App.vue to tell the app which layout to use.

App.vue

<template>
  <div id="app">    
    <component :is="layout">
      <router-view></router-view>
    </component>
  </div>
</template>

<script>

export default {
  name: "App",
  computed: {
    layout() {
      return this.$route.meta.layout || 'default-layout';
    }
  }
};
</script>

Default layout component

<template>
    <div>
        <TrialBanner v-if="$store.state.website.is_trial"/>
        <div class="page-body-wrapper" >
            <Sidebar :key="$store.state.user.is_admin" />
            <div class="main-panel">
                <Header />
                <div class="content-wrapper">
                    <slot></slot>
                </div>
            </div>
        </div>
    </div>
</template>
<script>
export default {
  name: 'DefaultLayout',
};
</script>

Sample customize page layout

<template>
    <div>
        <TrialBanner v-if="$store.state.website.is_trial"/>
        <div class="page-body-wrapper" class="p-0">
            <div class="main-panel" class="m-0 w-100">
                <div class="content-wrapper" class="p-0">
                    <slot></slot>
                </div>
            </div>
        </div>
    </div>
</template>
<script>
export default {
  name: 'CustomizeLayout',
};
</script>

Main.js: register layout components as global components

import DefaultLayout from '@/layouts/DefaultLayout.vue';
import CustomizeLayout from '@/layouts/CustomizeLayout.vue';

Vue.component('default-layout', DefaultLayout);
Vue.component('customize-layout', CustomizeLayout);

Router.js: routes define the layouts for each route

const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView,    
  },
  {
    path: '/customize',
    name: 'customize',
    component: CustomizeView,
    meta: {
      layout: 'customize-layout'
    }
  }
];

The <slot></slot> in each layout component is where the View will render. You can also have multiple named slots and named views if you want to render different components in areas per layout.

tony19
  • 125,647
  • 18
  • 229
  • 307
Steven B.
  • 8,962
  • 3
  • 24
  • 45