Using v-if for every children route in vue.js - vue.js

I would like to show a certain div for every child route of the route
So I thought simply adding something like this would work, but it does not:
<div v-if="$route.path == '/news/:child'">
</div>
So any route that is nested under /news/ still does not show that <div>
How can I display that div for every child route of the /news route?

So actually this will work if I set v-if="$route.path.includes('/news/')", thus div only shows in children routes (not in parent).

Use Vue Nested Routes:
const routes = [
{
path: '/news',
component: NewsComponent,
children: [
{
path: ':child',
component: ChildComponent,
},
]
}
]
// NewsComponent
<template>
<div>
My News Component
<router-view />
</div>
</template>
// ChildComponent
<template>
<div>
My Child Component
</div
</template>
Will render:
<div>
My News Component
<div>
My Child Component
</div>
</div>

Related

Vue Nested Route router-view not working if parent router-view is rendered in a slot

I have a ContainerMain component in which the RouterView is rendered as a simple default slot in a MainLayout Component.
// routes.ts
const mainMenuRoutes = [{
path: "blood-drop",
name: RouteNameMenu.MENU_BLOOD_DROP,
component: BloodDropMain,
children: [
{
path: "checkups",
name: RouteName.BLOOD_CHECKUPS,
component: CheckupResults,
}
],
}];
{
path: "/",
name: RouteName.MENU_MAIN,
component: ContainerMain,
children: mainMenuRoutes,
}
// ContainerMain.vue
<template>
<!-- <RouterView /> --> THIS WILL WORK !!!
<MainLayout> ---> THIS DOESN'T WORK !!!
<RouterView />
</MainLayout>
<div></div>
</template>
If I navigate to '/blood-drop' I get the BloodDrop Component rendered successfully. But when I navigate or refresh to '/blood-drop/checkups' I get an error.
// BloodDropMain.vue
<template>
<div class="blood-drop-container">
...etc
<div class="content">
<RouterView />
</div>
</div>
</template>
enter image description here
If however I move out the parent <RouterView /> outside of <MainLayout></MainLayout> it will work, no error, except of course not having the correct UI.

Problem with Nested Router View Transitions

I have two navigation menu in my page structure, one is main header navigation and other one is in one of those main navigated page. I added transition onto both router views but child router view's transition doesn't work only parent. Let me explain with codes;
my routes:
const routes = [
{
path: '/',
component: () => import('layouts/MainLayout.vue'),
children: [
{ path: '', component: () => import('pages/Home.vue') },
{
path: '/features',
redirect: '/features/f1',
component: () => import('pages/Features'),
children: [
{ path: 'f1', component: () => import('pages/Feature1') },
{ path: 'f2', component: () => import('pages/Feature2') },
{ path: 'f3', component: () => import('pages/Feature3') },
{ path: 'f4', component: () => import('pages/Feature4') }
]
},
{ path: 'pricing', component: () => import('pages/Pricing')},
{ path: 'register', component: () => import('pages/Register')}
]
}
]
this is parent router view in main layout
<q-page-container class="l-background overflow-hidden">
<router-view ref="main" v-slot="{ Component, route }">
<transition name="fade-transform" mode="out-in">
<component :is="Component" :key="route.path" />
</transition>
</router-view>
</q-page-container>
and this is the component which includes child router view and its navigation:
<template>
<q-page class="flex flex-center">
<q-list class="custom-list">
<div class="relative-position full-height">
<feature-button v-for="(navi, index) in manufacturingNavi" :key="index" :nav="navi" buttonText="sample" />
</div>
</q-list>
<div class="row q-gutter-x-md justify-between full-width q-px-xs">
<div class="col-auto relative-position full-height self-center">
<p class="text-h4">What can I do<br/> with this app?</p>
</div>
<div class="col-8">
// must change only this part of page via router view but this transition doesn't work..
<router-view ref="feature" v-slot="{ Component, route }">
<transition name="fade-transform" mode="out-in">
<component :is="Component" :key="route.path" />
</transition>
</router-view>
</div>
</div>
</q-page>
</template>
child routes of features page work but not as expected. I expect that when I click one of child routes, only child route's component (that part of page) changes with its transition property. When child route clicked parent routes transition works (whole page changes). When I remove transition from child router view, nothing changes. It behaves like child router view doesn't exist. Where is my mistake?
I use vue 3 and vue router 4. Thank you.
I tried to explain by visualizing below.
Reason found. Using key attribute on parent router-view (in main layout in my case), always its transition props run. I removed key attributes from all router-views and problem solved.

can't rendering router children

i have a router called '/shop' and the children is /list/:id for the component named is listproduct
but when i render on the link i go like mylocalhost/shop/list/0812018381 it does render ?
here is my routes
{
path: '/shop',
name: 'shop',
component: () => import('./components/shop.vue'),
children: [
{
path: '/list/:id',
name: 'list',
component: () => import('./views/detail.vue'),
},
],
}
the component on my shop is something like this
<b-col>
<div class="thiscaption my-4 p-2">
<b-link :to="`/shop/${product._id}`">
<h4>{{ product.productName }}</h4>
</b-link>
<span>
{{
product.desc
.split(' ')
.slice(0, 8)
.join(' ')
}}...</span
>
<br />
<span>
<b>${{ product.price }} </b>
</span>
<br />
<b-button type="submit" variant="primary" class="p-2
my-4">add to cart</b-button>
</div>
</b-col>
i have tried to move that component list to not in children of shop, it was work, but when i use it on children shop, it doesnt render and work
If you use the children property of a route, any child routes are mounted in the parent component. In your case it means it is mounted in shop.vue. To be able to mount the component in the parent component, the parent component must contain a <router-view /> element.
Take for example the following components:
<!-- App.vue -->
<template>
<div id="app">
<span>Start App.vue</span>
<router-view/>
<span>End App.vue</span>
</div>
</template>
<!-- ParentComponent.vue -->
<template>
<div class="parent-component">
<span>Start Parent component</span>
<router-view/>
<span>End Parent component</span>
</div>
</template>
<!-- Child1.vue -->
<template>
<div class="comp-child1">Child1.vue</div>
</template>
Furthermore, we have the following router:
// router.js
import Vue from "vue";
import VueRouter from "vue-router";
import ParentComponent from "./components/ParentComponent";
import Child1 from "./components/Child1";
import Child2 from "./components/Child2";
Vue.use(VueRouter);
const routes = [
{
path: "/",
component: ParentComponent,
children: [
{
path: "",
redirect: "/child1"
},
{
path: "child1",
component: Child1
},
{
path: "child2",
component: Child2
}
]
}
];
export default new VueRouter({
routes
});
In this case, App.vue is the root component, because this is defined in main.js. The router says that child1 is a child route from /, which renders component ParentComponent. Therefore we will see the start and end of app.vue. Nested in there we will see the start and end of ParentComponent. Then nested inside of that, we see Child1. Without router-view in either of these components, there would be no place for their children to be mounted.

render a Vue slot in a layout from component

I'm having problems with a named slot. This seems like it should work. In the code below I'm trying to use a named slot "sidebar". I would expect my sidebar slot content to show up between the Sidebar starts and Sidebar ends text but nothing shows up in that slot. Everything renders in the main slot.
Here's my code.
route...
{
path: "/test",
name: "test",
meta: {
layout: "test-layout"
},
component: () =>
import("#/pages/Test.vue")
},
and App.vue template...
<template>
<div id="app">
<component :is="layout">
<router-view />
</component>
</div>
</template>
and test-layout...
<template>
<div>
<div>
<h1>Sidebar starts</h1>
<slot name="sidebar"/>
<h1>Sidebar ends</h1>
</div>
<div class="container">
<h1>Content starts</h1>
<slot/>
<h1>Content ends</h1>
</div>
</div>
</template>
and page Test.vue...
<template>
<test-layout>
<span slot="sidebar">sidebar slot content {{forecast.todaySummary}}</span>
<div>main slot content {{forecast.currentSummary}}</div>
</test-layout>
</template>
<script>
import api from "#/js/web-services";
export default {
data() {
return {
forecast: null
};
},
created() {
api.getDailyForecast().then(response => {
this.forecast = response.data;
});
}
};
</script>
and the import in my main.js
import TestLayout from "./layouts/test-layout.vue";
Vue.component('test-layout', TestLayout);
Why isn't my sidebar slot working?
UPDATE
If I get rid of the two lines in main.js and add
import TestLayout from "#/layouts/test-layout.vue";
and
export default {
components: { TestLayout },
data() {...
to Test.vue then it works.
In your router file you are using layout: "test-layout" this means what ever comes in your vue component will be rendered in base test-layout.
There are two ways as far as I know to render the layouts.
Do not define layout in router file and on parent component define named slots like this<slot #header></slot><slot #body></slot> then every slot will be rendered within this (test-layout) layout, and then in your each component extend like this <test-layout><template header>Header content</template><template body>Body content</template></test-layout>.
Defining layout in router file like you did, you can not further use in slots in that layout, you can just import other components e.g <template><Component1><Component2> </template>

Getting a value from a nested template in vue

So basically I have something like this in my home page
<template>
<div id="body">
<sideBar :menu="menu" :tableName='tableName' titleOfPage='titleOfPage'></sideBar>
<div id="menu">
HOME PAGE
</div>
</div>
</template>
In the sidebar template you can select your page. It will forward you this template
<template>
<div id="body">
<sideBar :menu="menu" :tableName='tableName' :titleOfPage='titleOfPage'></sideBar>
<div id="main">
<h1>{{ titleOfPage }}</h1>
....
I need the sidebar template to set the titleOfPage as it corresponds to the page clicked. I tried different ways but didn't manage. I appreciate the help by explaining me how to solve this issue.
The Vue docs recommend not using $router directly but instead configuring props to pass to the routed components:
const routes = [
{ path: '/', redirect: '/page-a', component: { template: `<router-view></router-view>` }, name: 'Home' },
{ path: '/page-a', component: Page, props: { titleOfPage: 'Page A' }},
{ path: '/page-b', component: Page, props: { titleOfPage: 'Page B' }},
];
If your props are dynamic and depend on the current route, you can pass a function to the props property of each route configuration:
{ path: '...', component: ..., props: (route) => ({ query: route.query.q }) }
To solve your issue, you can simply create a page component which receives the props from the router and render your sidebar component in its template:
<!-- template for page component -->
<template>
<div id="body">
<sideBar :menu="menu" :tableName='tableName' :titleOfPage='titleOfPage'></sideBar>
<div id="main">
<h1>{{ titleOfPage }}</h1>
<!-- ... -->
</div>
</div>
</template>
DEMO: stackblitz