Vue router doesn't generate the correct link - vue.js

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?

Related

nested router with lazy load not work propertly

I am new to Vue and want to navigate Product child routes, but it do not work & get NotFound page instead.
So my question is how to make it properly.
Or can someone give some details. Thanks
Online Editor
index.js
const routes = [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/products',
component: () => import('../views/ProductPage.vue'),
children: productRouter
},
{
path: '/**',
component: NotFound
}
]
product.js
const productRouter = [
{
path: '',
name: 'products',
component: ProductPage
},
{
path: 'product/:id',
name: 'ProductDetails',
component: ProductDetails
},
{
path: '**',
component: NotFound
}
]
There are some little mistakes leading to your unexpected result.
In product.js router you should not prefix again with products since it is already in the scope of the /products route. The NotFound route is also not needed in this definition since the parent's NotFound already matches the same route patterns. You can rewrite the product router definition like below :
const productRouter = [
{
path: ':id',
name: 'ProductDetails',
component: ProductDetails
}
]
Then, in ProductList.vue, you should rewrite your router-link as below :
<router-link :to="`/products/${item.id}`"> {{ item.description }} </router-link>
Finally, in ProductPage.vue, you are missing the <router-view></router-view> needed to render your child routes as explained in the vue router documentation.. You could rewrite it like below :
<template>
<div id="productPage">
<h1>This is an Product Page</h1>
<ProductList :items="products"> </ProductList>
<router-view></router-view>
</div>
</template>

Dynamic router link changes *slash* to %2F

I've got little problem with dynamic router link. I got array of objects(pages) from API, and one of them is my home:
{
name:"dynamic"
parent_id:0
partners:null
slug:"/"
}
then using v-for I want create router-link like this:
<div v-for="page in pages">
<router-link
:to="{ name: page.name, params: { slug: page.slug }}"
class="v-list__link"
>
</div>
Problem is when I render page this link to home is not <a href="/"> as I expected but it is with endocing reference: %2F => <a href="%2F">
router.js
export default new Router({
scrollBehavior (to, from) {
return { x: 0, y: 0 }
},
mode: 'history',
routes: [
{
path: '/:slug',
name: 'dynamic',
component: Dynamic
},
{
path: '/',
name: 'dynamic',
component: Dynamic
},
{
path: '/contact',
name: 'contact',
component: Contact
}
]
})
does anyone know how to solve it ?
The route's path is /:slug. When resolved with slug equal to / then you get // as the final path, except it will be resolved to /%2F since the params will be encoded with encodeURIComponent.
Remove the leading slash from the slug param:
page.slug.replace(/^\//, '')
You also have two routes with the same name, this isn't allowed. The second dynamic route cannot be resolved by name.

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 moves to route but loads wrong component

I have the following router config:
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'notselected',
component: PackageUnselected
},
{
path: '/package/:id',
children: [
{ path: 'meta', name: 'packageMeta', component: ViewPackageMeta },
{ path: 'readme', name: 'packageReadme', component: PackageReadme },
{ path: 'docs', name: 'packageDocs', component: PackageDocs },
{
path: 'playground',
name: 'packagePlayground',
component: PackagePlayground
}
]
},
{
path: '/about',
name: 'about',
component: About
},
{
path: '*',
redirect: '/'
}
]
});
And when I'm at the root route it correctly identifies the route name as notselected. When I route to any of the "/package/[id]" routes though it continues to load the PackageUnselected component instead of the appropriate route (aka, ViewPackageMeta, PackageDocs, etc.).
Now at the point in the DOM where I want the route to insert the route's component I have the following template:
<v-tab-item v-for="item in tabs" :id="'tab-item-' + item" :key="item" exact>
item: {{item}}
<router-view :selectedPackage="selected"></router-view>
</v-tab-item>
And because I have installed vuex-router-sync it's easy to see the route state at any given time. So when clicking on the route that should load PackageDocs:
But the component view window of vue-devtools looks like this:
the highlighted area shows that NO component has been loaded into the tabs. I then tried adding a component to the definition of the parent route /package/:id:
{
path: '/package/:id',
component: Packages,
children: [
{ path: 'meta', name: 'packageMeta', component: ViewPackageMeta },
{ path: 'readme', name: 'packageReadme', component: PackageReadme },
{ path: 'docs', name: 'packageDocs', component: PackageDocs },
{
path: 'playground',
name: 'packagePlayground',
component: PackagePlayground
}
]
},
I then had to create the world simplest component for Packages:
<template>
<view-router-view></view-router-view>
</template>
This results in the following:
Hmmm. Can't figure out what to do next. Anyone have any pointers?
When I route to any of the "/package/[id]" routes though it continues
to load the PackageUnselected component instead of the appropriate
route (aka, ViewPackageMeta, PackageDocs, etc.).
That is the correct behavior of the vue-router.
Children can only be loaded when URL paths are:
/package/[id]/meta
/package/[id]/readme
/package/[id]/playground
/package/[id]/docs
Parent path may not have component defined if you have configured redirect option and your user, who opens /package/[id] will be redirected to your default path (could be anything).
Lets move to the next part of your question...
<v-tab-item v-for="item in tabs" :id="'tab-item-' + item" :key="item" exact>
item: {{item}}
<router-view :selectedPackage="selected"></router-view>
</v-tab-item>
You don't need to create here 4 different <router-view> tags, you just need one where all your children components will display html code.
<v-tab-item v-for="item in tabs" :id="'tab-item-' + item" :key="item" exact></v-tab-item>
<router-view></router-view>
Now you will have only one router-view and it's the default one. When user clicks on any of your tabs you just need to this.$router.push a new path on #click-event in Packages component. That's it.
I have created a simple example (codepen) to demonstrate how this task can be solved:
Vue.use(VueRouter);
// Components
let MetaPackages = {
mounted() { console.log('Mounted MetaPackages...'); },
template: `<div>MetaPackages...</div>`,
};
let DocsPackages = {
mounted() { console.log('Mounted DocsPackages...'); },
template: `<div>DocsPackages...</div>`,
};
let ReadmePackages = {
mounted() { console.log('Mounted ReadmePackages...'); },
template: `<div>ReadmePackages...</div>`,
};
let Packages = {
mounted() { console.log('Mounted Packages... ' + this.$route.path); },
template: '<div>Packages (parent) screen...<br/><router-view></router-view></div>',
};
// Router
const router = new VueRouter({
mode: 'hash',
routes: [
{
path: "/packages/:id",
component: Packages,
children: [
{path:"meta", component: MetaPackages},
{path:"docs", component: DocsPackages},
{path:"readme", component: ReadmePackages}
]
}
]
});
// Vue instance
const vm = new Vue({
el: '#app',
router,
components: {Packages, MetaPackages, DocsPackages, ReadmePackages}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.0.2/vue-router.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<router-link to="/packages/100/meta">Meta</router-link>
<router-link to="/packages/100/docs">Docs</router-link>
<router-link to="/packages/100/readme">Readme</router-link>
<hr/>
<router-view></router-view>
</div>

routing with params in vuejs using router-link

I am trying to build a spa using vuejs in which I have a list of users now when I click a user it should route to a new page with user details of the particular user how to params the user id in router-link
You can pass params in router link using
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
Here "name" key parameter defines the name of the route and "params" key defines the parameters you need to send with that route.
If you need to use Route Path instead of Route name, You can use.
<router-link :to="{ path: 'home', params: { userId: 123 }}">Home</router-link>
Reference
Looks like params: {...} doesn't work on non-named routes so to get that working I had to make my links like this:
<router-link :to="'/view-customer/' + customer.ID">
With ES6 template literals:
<router-link :to="`/books/${book.id}`"></router-link>
solution for non-named routes:
<router-link :to="{ path: 'register', query: { plan: 'private' }}"
>Register</router-link>
resulting in /register?plan=private
source: Documentation
I'm using this and it's works fine:
<router-link :to="'/home?id=' + customer.ID">
Also use the following code to retrieve it:
this.$route.query.id
router/index.js:
import VueRouter from 'vue-router'
import List from '../views/List.vue'
import Item from '../views/Item.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'List',
component: List
},
{
path: '/item/:id',
name: 'Item',
component: Item
}
}
]
List.vue:
<router-link :to="{ name: 'Item', params: { id: data.item.id }}">{{ data.item.id }}</router-link>
Item.vue:
<template>
id: {{ $route.params.id }}
</template>
<script>
return this.$route.params.id
</script>
Routes declaration
{path: '/insta-view/:name', name: 'instaFrontView', component: instaFrontViewComponent},
Bind parameter using the path
<router-link :to="'insta-view/'+ loginUserName" class="nav-link"> View</router-link>
Bind parameter using the name
<router-link :to="{ name: 'instaFrontView', params: { name: loginUserName }}" class="nav-link"> View</router-link>
export default {
data() {
return {
loginUserName: 'test',
}
},
}
Retrieve parameter in code
this.$route.params.name