Getting a value from a nested template in vue - vue.js

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

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.

How to extend the onClick handler behaviour for a `router-link` in vue3 router

I have a <router-link /> that I want to use to navigate to another page in a Vue 3 application, but I also want to run another function when this link is clicked.
Right now I have to use an extra <span /> element to wrap the <router-link /> and add the #click attribute there to rely on event bubbling. Adding the #click handler on <router-link /> causes the router link not to work and the browser thinks it is just a normal anchor href.
<span #click="handleClose(imageId)">
<router-link
:to="{name: 'image', params: {'imageId': imageId}}"
class="permalink">
Permalink
</router-link>
</span>
Is there a better way?
You must use the .native modifier on the #click event of router-link. The reason is quite simple - router-link is a Vue component but it does not emit a click event. Therefore you have to listen for the native click event coming from the browser.
https://github.com/vuejs/vue-router/issues/800
var router = new VueRouter({
routes:
[
{path: '/', component: {
template: '#first',
methods:
{
showAlert(text)
{
window.alert(text);
}
}
}},
{path: '/second', component: {
template: '#second',
methods:
{
showAlert(text)
{
window.alert(text);
}
}
}},
]
});
new Vue(
{
template: '#main',
router: router,
}).$mount('#app');
<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">test</div>
<template id="main">
<div>
<router-view></router-view>
</div>
</template>
<template id="first">
<router-link to="/second" #click.native="showAlert('second')">GOTO second</router-link>
</template>
<template id="second">
<router-link to="/" #click.native="showAlert('first')">GOTO first</router-link>
</template>
To avoid potential weird concurrency bugs (the view change could happen before your method being called, method which would then be attached to an unmounted component), I would do a programmatic navigation in your method:
<template>
<button type="button" #click="handleClose(imageId)">
Permalink
</button>
</template>
<script>
import router from '#/wherever/your/router/is/initialized';
export default {
methods: {
handleClose(imageId) {
// Do your stuff
router.push({ name: 'image', params: {'imageId': imageId}});
}
}
}
</script>

Using v-if for every children route in 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>

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.

Vue-Router: Nested routes not displaying

When using nested routes, the component does not display. If I do not use nested route, the component displays as expected. Any ideas on what I may be doing wrong with nested route?
import ManufacturersReport from "#/components/ManufacturersReport";
import Reports from "#/components/Reports";
Vue.use(Router);
export default new Router({
routes: [
{
path: "/reports",
name: "Reports",
component: Reports,
children: [
{ path: "manufacturer_report", component: ManufacturersReport }
]
}
],
mode: "history"
});
<template>
<header class="header">
<h1>Reports</h1>
<div id="nav">
<router-link to="/reports/manufacturer_report">MF Report</router-link>|
</div>
</header>
</template>
I got it working by adding <router-view></router-view> to my template code.
<template>
<header class="header">
<h1>Reports</h1>
<div id="nav">
<router-link to="/reports/manufacturer_report">MF Report</router-link>|
<router-link to="/ping">Reports</router-link>
<router-view></router-view>
</div>
</header>
</template>