Child route not showing in Vue-router - javascript

I've following object in Vue router.
{
path: "/books",
name: "books",
component: Books,
children: [
{
path: ":id",
name: "books.detail",
component: BookDetail,
}
]
}
Within Books.vue component, there're <router-link> that upon clicking each; it should go to its detail view.
<router-link :to="{ name: 'book.detail', params: { id: 5 }}">
<h2>Book Name</h2>
</router-link>
Similarly in App.vue I've following <router-view>.
<div class="books">
<router-view></router-view>
</div>
When I click <router-link> the path gets updated but the respective BookDetail Page doesn't show up.
It's first time I am integrating routers within a project and couldn't figured out how to solve it, even going in depth reading the documentation.

In Books.vue there needs to be an additional <router-view> to show the nested route component. Without it, you would get the behavior you describe.
Books.vue
<template>
<div>
Books
<router-view></router-view>
</div>
</template>
Or if you didn't want nested routing, define the detail page as a separate route:
{
path: "/books",
name: "books",
component: Books
},
{
path: "/books/:id",
name: "books.detail",
component: BookDetail
}
(Note: There's also a typo in the <router-link> (book instead of books) but since you were able to see the correct route path, maybe that's just a typo in your post.)

Related

Save the open state of tabs in vue js

I am creating a project. I've to work with many routes and tabs inside it. My problem is that I want my browser to remember that which tab was opened before refreshing the page.Suppose I have 3 tabs on 1 page and I opened the 2nd or 3rd tab, than I refresh the page it kick me back to 1st tab. How to prevent this.Is their any solution ?
Use child routes. Each tab would content a <router-view> element, which corresponds to a page within a page.
See vue-router docs on Nested Routes
const routes = [
{
path: '/my-page',
component: MainPage,
children: [
{
path: 'tab1',
component: Tab1Content,
},
{
path: 'tab2',
component: Tab2Content,
},
],
},
]
<!-- On /my-page/tab-2, Tab2Content will be rendered in the <router-view> -->
<template>
<v-tab>
<router-view /> <!-- Sub route -->
</v-tab>
</template>

How to add text to router-link in vueJS

I'm trying to add some text to my "to" attribute using router-link. The code that I've written is
<router-link :to="camp._id" class="btn btn-primary">Know more</router-link> // it redirects to the route localhost/23bjsaki24r...
My requirement is to redirect the user to route - localhost/campgrounds/23bjsaki24r... instead of localhost/23bjsaki24r...
How can I add the string "campgrounds" before camp._id? Thanks
P.S: I'm using Vuejs
Hahaha, nvm, I dug through the vue-router docs and found the solution to it.
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
This code snippet gave me a clearer understanding as to how to add additional parameters to my ":to" attribute.
The solution to my problem is
<router-link :to="{ name: 'Campground', params:{id:camp._id}}" class="btn btn-primary">Know more</router-link>
Where the name: -takes in the component name and the params: -takes in the additional params that I've defined in my vue-router file.

Vue.js - switching from one component to another

I'm quite new to vue.js.
I have a page that lists details of a list of people, with an 'Edit' button against each person.
When I click the Edit button, I want to switch to another page which shows a form for editing the selected person's details.
I'm not sure what is the best way to do this. I'm using Bootstrap and Router in my solution.
Option 1: I thought it would be straightforward to route to '/person/:id' when clicking the Edit button, but not sure how to do this from the click handler method.
Option 2:
Below is the main component, where I'm trying to switch between the two components 'PersonsList' and 'EditPersonData' upon receiving an event from either. PersonsList is emitting the event successfully, but I'm not sure how to listen to it here and switch to EditPesonData component.
Home.vue
<template>
<div class="home">
<h1 class='home-text'>
{{message}}
</h1>
<component v-bind:is="component"/>
</div>
</template>
<script>
import PersonsList from '#/components/PersonsList'
import EditPersonData from '#/components/EditPersonData'
export default {
name: 'Home',
data() {
return {
message: 'Welcome to Person Details!',
component: "PersonsList"
}
},
components: {
PersonsList,
EditPersonData
}
};
</script>
Any help would be very much appreciated.
Thanks
The best way would be to send the id as a param in the route /person/:id.
To do this, you can append the id of each list item, for example:
<div v-for="(user,index) in userList" :key="index">
<a :href="'/person/' + user.id">Edit</a>
</div>
Then, you would get it in the other component as this.$route.params.id in order to get more details about the user of this id.
Make sure you define the route in the router with the id param as follows: person/:id
UPDATE :
If you want to change the route on a click function:
<b-btn #click="editPerson(user.id)">Edit</b-btn>
And in the methods, add the function as follows:
editPerson(userId){
this.$router.push({
name: 'person',
params: { id: userId }
});
}

How to make router-link work with custom link component?

<base-link> component
I have a Vue component <base-link>, which I use every time I want to have an achor. It's mostly for applying styles specific to links, so that all the links across the whole page look the same without applying global styles.
Make <router-link> use <base-link>
When using <router-link> component to create a link, I cannot apply those styles (<base-link> styles are scoped) unless <router-link> uses my <base-link> component to create the anchor element.
Fortunately <router-link> provides tag attribute, which seems to do exactly that. Unfortunately I can't get it to work. I have 2 problems:
All my components are locally registered (I use ES6 modules with Webpack and import components locally every time I need them). <router-link> doesn't know what <base-link> component is and can't render it. Is there a way to inject a local component for <router-link> to use?
To solve problem #1, I thought it's enough to declare <base-link> component globally. Unfortunately it still doesn't work. This time <base-link> component gets rendered properly, but is still not functional - doesn't react to click events. It seems to me the problem is that it's href attribute isn't set at all. Is there a way to make <router-link> set it properly? (without setting it manually)
Question
How do I solve problems #1 and #2? I suspect #1 might be not possible, but I hope at least #2 is.
Code example
Here is a pen with code below, which illustrates both problems.
const router = new VueRouter({
routes: [
{
path: "/",
component: {
template: '<p>Homepage template</p>'
}
},
{
path: "/subpage",
component: {
template: '<p>Subpage template</p>'
}
}
]
});
// Globally registered BaseLink.
Vue.component('BaseLinkGlobal', {
props: {
href: String
},
template: `
<a
:href="href"
class="BaseLinkGlobal"
>
<slot />
</a>
`
})
const vue = new Vue({
el: "#app",
router,
components: {
// Locally registered BaseLink.
BaseLinkLocal: {
props: {
href: String
},
template: `
<a
:href="href"
class="BaseLinkLocal"
>
<slot />
</a>
`
}
},
template: `
<div>
<!-- 2 router links. One uses locally registered BaseLink
-- and the other one a globally registered one. -->
<nav>
<router-link
to="/"
tag="base-link-local"
>
Home
</router-link>
<router-link
to="/subpage"
tag="base-link-global"
>
Subpage
</router-link>
</nav>
<router-view />
</div>
`
});
You can create a base link component which can double as a normal a tag or <router-link> when you wish.
//Base link
<template>
<component :is="type" :class="{'base': type === 'a'}" v-bind="$attrs">
<slot></slot>
</component>
</template>
<script>
export default {
props: {
routerLink: {
type: Boolean,
default: false
}
},
computed: {
type() {
return this.routerLink ? 'router-link' : 'a'
}
}
}
</script>
<style scopex>
.base {
border: 1px solid red;
}
</style>
Usage
when you want to use it as a normal link just do not provide the router-link prop as below:
<base-link>This is a base a tag</base-link>
To use it as a router-link just add the router-link prop along with the to prop:
<base-link router-link to="/">This is router-link</base-link>
Explanation about the base-link component:
We use a component which is provided by vuejs to render a tag or router-link base on the truthiness of the routerLink prop.
A class of .base is added if it is a normal link i.e a
we bind $attrs which allows us to make the component more transparent i.e allows us to use attributes like href or to without passing them as props.
<base-link href="https://google.com">go to google</base-link>
You can have a look here for more explanation about usage of $attrs
This is for solving problem #2
The global component doesn't inherit the event listener of the router link. You can make it inherit by adding v-on="$listeners" to the global component.
// Globally registered BaseLink.
Vue.component('BaseLinkGlobal', {
props: {
href: String
},
template: `
<a
:href="href"
class="BaseLinkGlobal"
v-on="$listeners"
>
<slot />
</a>
`
})
The link works after adding it: https://codepen.io/jacobgoh101/pen/YvqJxL?editors=0010

Vue Router Linking Children from Children

I am currently trying to get this thing working with Vue Router.
The goal is:
If Nav#1 is clicked, a Component which includes another Router-Link with SubNav#1 preselected should appear.
I could get it to work in the way that if you click Nav#1, the Component with SubNav#1 with an already active class appeared. The problem is that the active class from Nav#1 is removed and it is not possible to navigate to Nav#2 or N#3. If I click on the Router-Link from Nav#2 or #3 nothing happens...
routes.js:
{ path: '/app', component: App,
children: [
{ path: 'Nav#1', component: Nav#1_Content,
children: [
{ path: 'SubNav#1', component: SubNav#1_Content},
{ path: 'SubNav#2', component: SubNav#2_Content}
]},
{ path: 'Nav#2', component: Nav#2_Content},
{ path: 'Nav#3', component: Nav#3_Content},
]}
+ custom linkActiveClass in new VueRouter instance.
Nav component:
<router-link to="Nav#1/SubNav#1">Nav #1</router-link>
<router-link to="Nav#2">Nav #2</router-link>
<router-link to="Nav#3">Nav #3</router-link>
Nav#1_Content component:
<template>
<div>
<nav>
<router-link to="SubNav#1" tag="div">SubNav#1</router-link>
<router-link to="SubNav#2" tag="div">SubNav#2</router-link>
</nav>
<router-view></router-view>
</div>
</template>
When you specify a value for the to prop on a <router-link> tag, you are specifying the exact path of the route to go to.
Since all of your example paths are under the /app root path, I'm not sure how you are getting any of these links to work.
That said, you need to get rid of the # signs in your route path definitions. When providing a path to Vue Router, it strips anything after the # sign and saves it as the $route.hash value.
So, use the full pathname in the to prop for your <router-link> tags and drop the # signs.
Here's a working fiddle.

Categories