Vue3 Nested RouterLink is not active on load - vue.js

I have the main <RouterView/> which is responsible for the main navigation of the site. Now, one of the routes has its children as well. So in this component I've created another <RouterView name="helper"/> - a named one. Inside the router it looks like this:
{
path: '/foo/:bar',
name: 'foo',
meta: { requiresAuth: true, title: 'Foo' },
component: FooView,
children: [{
path: '1',
name: 'foo-first',
components: {
'helper': FooFirst,
},
}, {
path: '2',
name: 'foo-second',
components: {
'helper': FooSecond,
},
}],
props: true,
}
Now, the problem is with the RouterLinks inside the component - they are not getting the active class on load, only if I click on them - after this they start behave properly. The code is the following
...
<nav>
<RouterLink
:to="{ name: 'foo-first', params: { bar: data.bar } }"
class="px-1 py-4 text-base sm:text-sm"
active-class="!text-red-600 !border-red-500"
>
Foo First
</RouterLink>
<RouterLink
:to="{ name: 'foo-second', params: { bar: data.bar } }"
class="px-1 py-4 text-base sm:text-sm"
active-class="!text-red-600 !border-red-500"
>
Foo Second
</RouterLink>
</nav>
...
What I'm trying to do - make the links become active on load as well, for instance, if I go to some.site/foo/bar/1, I want the first RouterLink to become active on load.

It turned out that inside the RouterLink to attribute you don't need to pass any params as they are already in the parent route. Once I got rid of them, it started working properly.

Related

Detecting named view is used

I am looking to build a layout with a dynamic side-bar. The sidebar on its own has its own template, but I do not want that to be rendered unless the underlying router-view is used. Below the pseudo-code:
<template>
<transition name="slide">
<div class="sidebar" v-if="showSidebar">
<SidebarHeader />
<router-view name="side"><router-view>
<SidebarFooter>
</div>
</transition>
<div class=main><router-view></router-view></div>
</template>
Is there any obvious way of achieving that? I failed to find any property or function on $router or $route object.
As a workaround I've made Sidebar component that has to be used for each sidebar view, but is there a better option?
It seems I found the answer - it requires a bit of trick int he routes:
{
path: '',
component: 'Layout',
children: [
{
path: '',
components: { default: SomeMainComponent },
children: [
{ path: '' },
{
path: '',
components: { side: SideBox },
children: [
path: 'hello',
component: HelloSidebox
]
}
]
}
]
}
That empty route {path: ''} is to prevent the next route from being displayed for the exact route match and only render SideBox component for any matching sub-routes.

Update the parent data when user navigates to a specific route path

I'm new in VueJs, trying to set up a web application with Vue-route, and want to update the <header> style when user navigates to a specific URL, whether using "URL bar" directly or "navigation bar". In this case, we have a parent component that contains height_status data and some <router-links> on template.
I've done the "navigation bar" part with $emit technique and it works well but then I've tried to use it on created lifecycle hook in order to update the header whenever the /home route is created but event listener will not reach the parent_component.
How can I solve this? Is there a better way to do that?
Please see the code below:
Parent_component.vue
<template>
<div id="app">
<router-link to="/home" #height_size_ctrl="change_height">Home</router-link>
<router-link to="/about">About us</router-link>
<router-link to="/contact">Contact us</router-link>
<header :class="height_status ? 'head-h-s' : 'head-h-m'"></header>
<router-view/>
</div>
</template>
<script>
export default {
name: "Parent_component"
},
data() {
return {
height_status: false
}
},
methods: {
change_height(h) {
this.height_status = h
}
}
}
</script>
router.js
Vue.use(Router)
export default new Router({
routes: [
{
path: '/home',
name: 'home',
component: Home
},
{
path: '/about',
name: 'about',
component: about
},
{
path: '/contact',
name: 'contact',
component: contact
}
]
})
home.vue
<template>
<h1>hello</h1>
</template>
<script>
export default {
name: 'home',
created: function(){
return this.$emit("height_size_ctrl", true)
}
}
</script>
You could also change the router:
router.js
{
path: '/home',
name: 'home',
component: Home,
meta: {
headerClass: 'head-h-s'
}
}
In your component
Parent_component.vue
computed: {
headerClass() {
return this.$route.meta.headerClass
}
}
Now headerClass is available in the template.
<header :class="headerClass"></header>
why don't you try class binding on route or route name something like:
<div :class="{'height_status': this.$route == '/home'}">Header</div>
or
<div :class="{'height_status': this.$route.name == 'Home'}">Header</div>
As #kcsujeet said, class binding is the good way we can do this. In this case we need to look at the condition this.$route.path. if value is equal to the /home select 'head-h-m, otherwise select .head-h-s.
<header class="head-sec" :class=" this.$route.path == '/home' ? 'head-h-m' : 'head-h-s'">
Also we're able to access other route defined properties using this.$route. I suggest take a look at the router.js file.
routes: [
{
path: '/home',
name: 'home',
component: Home
}

Vue-router and deeply nested routes

Given following Layout component:
Layout:
<template>
<div class="container">
<div class="sidebar-container">
<router-view name='sidebar'></router-view>
</div>
<div class="main">
<router-view></router-view>
</div>
</div>
</template>
Is there a way to specify in deeply nested route to use sidebar outlet?
const routes = {
path: '',
components: { default: SomeMainComponent },
children: [{
path: 'foo',
children: [{
path: 'bar',
components: { sidebar: BarSide }
}]
}]
}
It seems that router is only looking to resolve the router outlets of the direct route parent - if I move components: { side: BarSide } to the foo definition, then the component is rendered as expected. As is, component is not even being created.
Is there a way to achieve this?
JsFiddle: https://jsfiddle.net/xptkhf4z/5/ - clicking on a With helper link updates the route, keeps default component rendered but does not render the additional component in helper slot.
Although I don't have the full answer, you seem to have to include a component on each nested level. That can either be your page component or a layout component.
This should work:
const routes = {
path: '',
components: { default: SomeMainComponent },
children: [{
path: 'foo',
component: () => import('layouts/DummyLayoutComponent'),
children: [{
path: 'bar',
components: { sidebar: BarSide }
}]
}]
}
The DummyLayoutComponent should be a neutral layout, because it is added to the layout of SomeMainComponent.
I find it a little awkward that we seem to have to define an "empty" layout just to get this to work. But maybe I'm just missing an important point.

Vue Child is not loaded after route enter

This is my router structure
{
path: '/',
name: 'home',
component: Home
},
{
path: '/user/:id',
name: 'user',
component: User,
children: [
{
path: '',
name: 'page',
component: Page
},
.....
}
I used this in Home.vue to redirect (/user/12345)
<router-link
:to="{
name: 'user',
params: {id: user.userId}
}"
>
When I clicked this link in home page, it routes correct path however I can not render child component (Page.vue) However when I reload the page, child component is loaded successfully. (url is still same)
There is an only rendering issue when I click the link on the homepage. How can I get rid of this. Thanks in advance.
User.vue
<template>
<div>
<NavDrawer/>
<router-view></router-view>
</div>
</template>
Edit: Any help will be so beneficial for me. Thanks

Vue router doesn't generate the correct link

I'm very new in Vue.js and I have to modify an application I didn't write by myself :-/
So I just need to add a link in a vue.
The router is defined like that (excerpt):
export default new Router({
routes: [
....,
{
path: '/client/:idClient',
component: client,
children: [
{
path: 'sites',
name: 'client-sites',
component: clientSites
},
....
]
},
.....,
{
path: '/onduleur/:idOnduleur',
name: 'onduleur',
component: onduleur
},
....
]
})
The vue is declared like that:
....
<td><router-link :to="{ name: 'onduleur', params: { idOnduleur: equipement.id }}"> 1 {{ equipement.nom }}</router-link></td>
<td><router-link :to="{ name: 'client-sites', params: { idClient: equipement.client.idClient }}">{{ equipement.client.raisonSociale }}</router-link></td>
....
The first generated link is http://my_site.com/#/ instead of http://my_site.com/#/onduleur/12 whereas for the second link I actually have http://my_site.com/#/client/12/onduleurs.
According to the doc, I don't see what prevents the first link to be generated correctly.
Any idea about what I should check?