Vue Router: hide parent template when child is open - javascript

Im trying to install Vue.js with the router and im running into some view issues. I have a router.js with child routes. I want to use this method for simple breadcrumbs and generate a clear overview so i know which route belongs where.
Opening each route works like a charm, everything shows up. When i open /apps I get a nice view from my Apps.vue that displays App overview</h1>. But now im opening /apps/app-one and then I see the Apps.vue and AppOne.vue template. How can I prevent that both templates are displayed?
The vue components looks like this:
Router.js
import Router from 'vue-router';
import AppsPage from './components/Apps.vue'
import AppOne from './components/AppOne.vue'
import AppTwo from './components/AppTwo.vue'
export default new Router({
// mode: 'history',
routes: [
{
path: '/apps',
component: AppsPage,
children: [
{
path: '/apps/app-one',
component: AppOne,
},
{
path: '/apps/app-two',
component: AppTwo,
},
]
},
]
});
Apps.vue
<template>
<div id="app-overview">
<h1>App overview</h1>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'app_page'
}
</script>
App1.vue
<template>
<div>
<h1>App 1</h1>
</div>
</template>
<script>
export default {
name: 'app_one'
}
</script>
App2.vue
<template>
<div>
<h1>App 2</h1>
</div>
</template>
<script>
export default {
name: 'app_two'
}
</script>

Having your routes in a parent-child relationship means that the child component will be rendered inside the parent component (at the <router-view>). This is expected behavior.
If you do not want the parent component to be visible when the child route is active, then the routes should be siblings, not nested:
[
{
path: '/apps',
component: AppsPage,
},
{
path: '/apps/app-one',
component: AppOne,
},
{
path: '/apps/app-two',
component: AppTwo,
},
]
The structure of the routes reflects the way they are rendered on the page.

It's possible and pretty easy too.You can achieve this by followings:
<template>
<div>
<div v-show="isExactActive">
Parent component contents will be here
</div>
<router-view ref="rv"></router-view>
</div>
</template>
<script>
export default {
data() {
return {
isExactActive: true,
}
},
updated() {
this.isExactActive = typeof this.$refs.rv === 'undefined';
},
mounted() {
this.isExactActive = typeof this.$refs.rv === 'undefined';
}
}
</script>
Hope, this will be helpful.

Related

Why does every component in my page appears twice?

I have created a sort of First page for my project, but I don't know why it renders everything twice on my page:
here is my First.vue component that is used by the router as the first page:
<template>
<h1>Bienvenue</h1>
<router-view></router-view>
<div class="routing" v-if="this.$route.path == '/'">
<router-link to='/app'>Go to application</router-link>
<br>
<router-link to='/test'>Go to test</router-link>
</div>
</template>
and here is what I get on the page when I npm run serve
Does anyone knows where it comes from?
UPDATE
When I delete the router-view element, the components appear once but when I click on one of the links, it changes the URL of the page but the page in itself is not showing the component.
And when I try to put everything in my router-view, like this:
<template>
<router-view>
<div class="routing" v-if="this.$route.path == '/'">
<h1>Bienvenue</h1>
<router-link to='/app'>Go to application</router-link>
<br>
<router-link to='/test'>Go to test</router-link>
</div>
</router-view>
</template>
it appears once, but like the other case, when I click on a link, it is just changing the URL and not the page.
Here is my index.js to show you how my routes are defined:
import {createRouter, createWebHistory} from 'vue-router'
import App from '../App.vue'
import Test from '../Views/Test.vue'
import First from '../Views/First.vue'
export const router = createRouter({
history: createWebHistory(),
routes: [
{
path:'/',
name: 'First',
component: First,
},
{
path:'/test',
name: 'Test',
component: Test
},
{
path:'/app',
name: 'App',
component: App
}
]
})
Just to clarify what results I expect from my app:
When I run the project, I want to launch on a page with just a header saying 'Hello' at the top of the page and two links where I can either click on 'Go to the application' or 'Go to test'.
Then, when I click on one of the links, I want to see the content of the component (so either test or the app), but I don't want to see the header and the links anymore.
I am not sure but try this:
{
path: "/app",
component: () => import("../App.vue"),
name: "App"
},
{
path: "/test",
component: () => import("../Views/Test.vue"),
name: "Test"
},
{
path: "/",
component: () => import("../Views/First.vue"),
name: "First"
}
Update with sample code or you can refer to live code here.
// App.vue
const First = {
template: `<div class = "container" id="app">
<h1>Hi from First</h1>
<hr>
<router-link to="/foo">Foo</router-link>
<router-link to="/bar">Bar</router-link>
</div>
`
}
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
const routes = [
{
path:'/',
name: 'First',
component: First,
default: First
},
{
path:'/foo',
name: 'Foo',
component: Foo
},
{
path:'/bar',
name: 'Bar',
component: Bar
}
]
const router = new VueRouter({
routes
})
const app = new Vue({
router
}).$mount('#app')
// main.js
<div id="app">
<!-- route outlet -->
<!-- component matched by the route will render here -->
<router-view></router-view>
</div>

Vue router doesn't route to specified location

I'm using vue with vue-router and route doesn't work when routing to children route.
{
path: '/user',
name: 'User',
component: User,
children: [
{
path: 'profile',
component: Profile,
},
],
}
Programmatically routing to /user/profile
<template>
<div>
<button #click="goToUserProfile()">create new</button>
</div>
</template>
<script>
export default {
methods: {
goToUserProfile() {
this.$router.push('/user/profile') // Routing doesn't work
.catch(console.log);
},
},
};
</script>
give a route name "Profile" for "/user/profile"
{
path: '/user',
name: 'User',
component: User,
children: [
{
path: 'profile',
name: "Profile",
component: Profile,
},
],
}
navigation use route name
this.$router.push({name: "Profile"});
your User component should declare like this
User.vue
<template>
<div>
<p>this is user component</p>
<!-- your Profile component will replace this route-view -->
<route-view />
</div>
</template>
demo
https://codesandbox.io/s/falling-bash-6dl7m
Do your ensure that you put <router-view></router-view> in User Component template to make the nested (children) routes displayed.
<template>
<div>
<button #click="goToUserProfile()">create new</button>
<router-view></router-view> <!-- placeholder for children routes -->
</div>
</template>
Then you can access by both
this.$router.push('/user/profile') and this.$router.push({ name: 'UserProfile' })
As Vue router document states:
To render components into this nested outlet, we need to use the children option in VueRouter.
https://router.vuejs.org/guide/essentials/nested-routes.html
Hope this help.

How to pass data to vue router router-view?

Im using Vue Router. In my code I used to have:
<div v-bind:is="page.component_name" v-bind:page="page"></div>
Which worked, and the page data was passed to the component. But how do I do the same with a router-view? This doesn't seem to work:
<router-view v-bind:page="page"></router-view>
js:
var vm = new Vue({
...,
router : new VueRouter({
routes : [
{ path: '/foo', component: { template: '<div>foo</div>', created:function(){alert(1);} } },
//{ path: '/bar', component: { template: '<div>bar</div>', created:function(){alert(2);} } },
{ path: '/bar', component: Vue.component("ti-page-report") }
]
}),
...
});
vue-router has a dedicated page in docs on how to pass props to router-view.
Passing Props to Route Components
Example snippet from docs:
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User, props: true },
// for routes with named views, you have to define the `props` option for each named view:
{
path: '/user/:id',
components: { default: User, sidebar: Sidebar },
props: { default: true, sidebar: false }
}
]
})
If you are looking for simplified usage, props can still be passed the same way they are passed to any component. But component that is used for rendering the route (the one that is specified in route definition) should expect to receive the props.
Here is simple usage example of passing props to router-view:
I personally decided to use provide/inject feature: preserving reactivity with minimal overhead.
The component ("ti-page-report") that needs to access the props being sent just needs to add it:
<template>
<div>
<h1>Now you can access page: {{ page }}</h1>
</div>
</template>
export default {
name: "TiPageReport",
props: ['page'], // can now be accessed with this.page
...
};
See https://v2.vuejs.org/v2/guide/components-props.html for how to use props properly.

Passing boolean from vue router to its component

I am new to Vuejs. I try to trigger the transition, every time the Homepage router link is clicked by user. I read some of documentation of Passing Props to Route Components enter link description here, and still cannot get it work. I tested the transition is working. But it seems like the loaded boolean did not passed to my component correctly.
Router index.js
{
path: '/',
name: 'Home',
component: Homepage,
props: { loaded: true }
},
Homepage component:
<template>
<transition name='fade'>
<div class="rgba-blue-grey-strong container" v-show="loaded">
<p>Text with transition Every time user access Homepage component</p>
</div>
</transition>
</template>
<script>
export default {
name: "Homepage",
props:['loaded'],
data(){
return{
loaded: false,
}
}
}
You have loaded defined in both props and data object. Remove the one in your data object and it'll be fine.
<script>
export default {
name: "Homepage",
props:['loaded'],
data(){
return {
}
}
}
</script>

Vue.js - Dynamic component import in data and computed properties

I have component 'Page' that should display a component which is retrieved via its props.
I managed to get my component loads when I harcode my component path in my component data like this :
<template>
<div>
<div v-if="includeHeader">
<header>
<fv-header/>
</header>
</div>
<component :is="this.componentDisplayed" />
<div v-if="includeFooter">
<footer>
<fv-complete-footer/>
</footer>
</div>
</div>
</template>
<script>
import Header from '#/components/Header/Header';
import CompleteFooter from '#/components/CompleteFooter/CompleteFooter';
export default {
name: 'Page',
props: {
componentPath: String,
includeHeader: Boolean,
includeFooter: Boolean
},
data() {
componentDisplayed: function () {
const path = '#/components/my_component';
return import(path);
},
},
components: {
'fv-header': Header,
'fv-complete-footer': CompleteFooter,
},
}
</script>
But with the data I cannot refer to my props within my function as this is undefined.
I tried to used computed properties instead of data but I have the error "src lazy?0309:5 Uncaught (in promise) Error: Cannot find module '#/components/my_component'. But the module exists! But maybe not at that time ?
computed: {
componentDisplayed: function () {
const path = `#/components/${this.componentPath}`;
return import(path);
},
},
There must be away to deal with that but I am quite a beginner to vue.js :)
Instead of trying to import the component in your child component, instead import it in the parent component and pass the entire component as a prop.
<template>
<div :is="component" />
</template>
<script>
export default {
name: "page",
props: {
component: {
required: true
}
}
};
</script>
And in the parent
<page :component="component" />
and
import Page from './components/Page';
// and further down
data () {
return {
component: HelloWorld
}
}

Categories