Vue.js v3 passing data through router link - vue.js

I have an object in Portfolio.vue like this:
data() {
return {
portfolio: {
front: [
{ description: '1. project ', src: require("../assets/sample.jpg"), slug: 'first'},
{ description: '2. project', src: require("../assets/sample.jpg"), slug: 'second' },
{ description: '3. project', src: require("../assets/sample.jpg"), slug: 'third' },
]
}
}
}
Portfolio.vue:
<div class="">
<div v-for="(data,index) in portfolio.front" :key="index">
<router-link :to="'/portfolio/'+data.slug"> <div class="element" :data-description="data.description">
<img :src="data.src " alt="">
</div>
</router-link>
</div>
</div>
PortfolioProduct.vue
<template>
<div>
<p>I want to take data to here. In here, i have to reach the data like this: portfolio.front.description</p>
</div>
</template>
<script>
export default {
props: {
},
}
</script>
My routes:
const routes = [
{
path: "/portfolio",
name: "Portfolio",
component: Portfolio,
},
{
path: "/portfolio/:id",
name: "PortfolioProduct",
component: PortfolioProduct,
props: true,
},
];
I want to take data from Portfolio.vue to PortfolioProduct.vue , i couldn't solve. I'm using vue js3 , if you help me i will be glad. Thank you

You could probably use the template literal, changing the router-link would be like so:
<router-link :to="`/portfolio/${data.slug}`"> <div class="element" :data-description="data.description">

Related

Children of NuxtLink rendered twice (hydration error?)

My hunch is that there is some hydration mismatch where the FontAwesomeIcon was not rendered on the server (only the span) and then on the client both child nodes of the NuxtLink were rendered (the svg and the span), prompting Nuxt to render the span twice.
The console does not return an error, though.
Any thoughts on how to debug this?
This is the Vue component:
<template>
<ul v-if="routes.length > 0" class="col-span-2 flex flex-col">
<li v-for="(item, i) in routes" :key="item.name">
<NuxtLink :to="item.path" target="_blank">
<FontAwesomeIcon :icon="item.icon" class="mr-3" fixed-width />
<span>{{ item.title }}</span>
</NuxtLink>
</li>
</ul>
</template>
<script lang="ts">
export default defineComponent({
props: {
links: {
type: Array,
default: () => ["instagram", "facebook", "email"],
},
},
computed: {
routes() {
return [
{
name: "instagram",
path: "https://www.instagram.com/insta.name/",
title: "Instagram",
icon: ["fab", "instagram"],
},
{
name: "facebook",
path: "https://www.facebook.com/fb.name",
title: "Facebook",
icon: ["fab", "facebook"],
},
{
name: "email",
path: "mailto:hello#example.com",
title: "Email",
icon: ["fas", "envelope"],
},
].filter((e) => this.links.includes(e.name));
},
},
});
</script>

How to display components of a child `router-view` that is nested within parent `router-view` in Vue JS?

I am trying to create a side menu (Dashboard's side menu with content) and I have to use multiple router-view.
First router-view is in App.vue that contains all the component.
<div id="app">
<router-view></router-view>
</div>
and the second router-view exists within above router-view as:
<div class="dashboard">
<Sidebar />
<div class="content">
<router-view name="content"></router-view>
</div>
</div>
According to below router/index.js code, if user visits / link, he will be redirected to dashboard page.
const routes = [
{
path: "",
name: "Dashboard",
component: dashboard,
},
{
path: "/messages",
name: "Messages",
components: {
content: Messages,
},
},
{
path: "/profile",
name: "Profile",
components: {
content: Profile,
},
},
{
path: "/settings",
name: "Settings",
components: {
content: Settings,
},
},
{
path: "/dashboard",
name: "Overview",
components: {
content: Overview,
},
},
];
and within above Sidebar component, there're links that upon clicking it shows the content of that link on right side (as in dashboard):
<div class="sidebar">
<div class="title">
Simple Sidebar
</div>
<div class="menu-items">
<router-link to="" active-class="active" tag="button" exact class="side-btn">
<div class="link-container">
Overview
</div>
</router-link>
<router-link to="/messages" active-class="active" tag="button" exact class="side-btn">
<div class="link-container">
Messages
</div>
</router-link>
// ....
</div>
</div>
for the second router-view I added a name as :
<router-view name="content"></router-view>
and then I identified it in router/index.js as:
{
path: "/messages",
name: "Messages",
components: {
content: Messages,
},
},
but it didn't work.
Can anyone help me debug and solve this issue, thank you in advance.
The nested route requires children route configs, which is missing from Dashboard's route config.
Move the route config of Messages into Dashboard's children array:
const routes = [
{
path: "",
name: "Dashboard",
component: dashboard,
children: [
{
path: "/messages",
name: "Messages",
components: {
content: Messages,
},
},
]
},
//...
]

Optional route params lost when access child route components Vue 2

I got a problem with optional route params, that route param (id) is lost when I access the child component
this is my route config on the router
{
path: "route/:id?",
component: () => import("*****"),
props: true,
children: [
{
path: "/",
redirect: { name: "*****" }
},
{
path: "information",
component: () => import("****")
},
]
},
this is my route expected companies/1/description etc
is there something wrong with my code?
this is how I push the router
it shows success like that companies/1/information but if i go through to another child route.. this param is lost like companies/direction
If I understand it correctly you expect the <router-link> placed inside your Company component to somehow "inherit" route params from the current route automatically.
Unfortunately this is not how it works with optional params - it would work with non-optional params but optional params must be passed explicitly...
:to="{ name: link.routeName, params: { id: $route.params.id } }"
const companies = Vue.component('companies', {
template: `
<div id="app">
<router-link to="/companies/1">Company 1</router-link>
<router-link to="/companies/2">Company 2</router-link>
<router-view></router-view>
</div>
`
})
const company = Vue.component('company', {
props: ['id'],
template: `
<div id="app">
<h4> {{ id }} </h4>
<h4> {{ $route.fullPath }} </h4>
<router-link :to="{ name: 'adminBusinessProfileInformation', params: { id: $route.params.id } }">Information</router-link>
<router-link :to="{ name: 'adminBusinessProfileDescription', params: { id: $route.params.id } }">Description</router-link>
<router-view></router-view>
</div>
`
})
const child = Vue.component('child', {
template: `
<div>
Child component
</div>
`
})
const router = new VueRouter({
mode: 'history',
routes: [{
path: '/',
redirect: 'companies'
},
{
name: 'companies',
path: '/companies',
component: companies
},
{
path: '/companies/:id',
component: company,
props: true,
children: [{
path: "/",
redirect: {
name: "adminBusinessProfileInformation"
}
},
{
path: "information",
component: child,
name: "adminBusinessProfileInformation"
},
{
path: "description",
component: child,
name: "adminBusinessProfileDescription"
}
]
}
]
})
new Vue({
el: '#app',
router,
})
<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">
<router-link to="/companies/1">Company 1</router-link>
<router-link to="/companies/2">Company 2</router-link>
<router-view></router-view>
</div>

Nested route of categories in Vue.js

What is an appropriate way to achieve a nested "n" levels of routes based on currently selected category ?
I would like to properly access the routes, so my URL would look like this:
/categories
/categories/outfit/
/categories/outfit/jackets/
/categories/outfit/jackets/mountains/
/categories/outfit/jackets/mountains/you_get_the_idea
I have a list of categories like so:
const categories = [
{
name: 'outfit',
childs: [
{ name: 'jackets',
childs: [
{ name: 'mountains' }
]
},
{ name: 'pants', childs: ['many subcategories'] },
{ name: 'boots', childs: ['many subcategories'] }
]
},
{
name: 'knives',
childs: [
{ name: 'hunting' },
{ name: 'souvenirs' },
{ name: 'kitchen' },
{ name: 'skinning' },
{ name: 'throwing' }
]
}
]
I have a main page of Categories (TOP LEVEL):
<div class="col-6" v-for="category in categories" :key="category.id">
<div class="block q-pa-md">
<router-link :to="'/categories/' + category.slug">
<h4>{{ category.name }}</h4>
</router-link>
</div>
</div>
And there is a nested page for 1st level of childs:
<h1>{{ category.name }}</h1>
<q-img :src="category.image"/>
<p>{{ category.description }}</p>
<div class="row q-col-gutter-md">
<div class="col-md-4 col-xs-6" v-for="subcategory in category.childs" :key="subcategory.id">
<div class="block q-pa-md">
<router-link :to="'/categories/' + subcategory.id">
<h4>{{ subcategory.name }}</h4>
</router-link>
</div>
</div>
</div>
How would I do some repeating nested childs ?
Dynamic Route Matching feature of Vue router allows to define a dynamic parameter which captures more than one segment of the path by defining your route as /categories/:categoryId+ (router uses path-to-regex to match)
When defined this way, route as /categories/outfit/jackets/mountains will have a categoryId parameter with value outfit/jackets/mountains, which can be passed into the component, easily parsed and worked with...
See my example below:
Vue.config.devtools = false
Vue.config.productionTip = false
const categories = [{
name: 'outfit',
childs: [{
name: 'jackets',
childs: [{
name: 'mountains'
}]
},
{
name: 'pants',
childs: [{
name: 'short'
}, {
name: 'long'
}]
},
{
name: 'boots',
childs: [{
name: 'barefoot'
}, {
name: 'mountains'
}]
}
]
},
{
name: 'knives',
childs: [{
name: 'hunting'
},
{
name: 'souvenirs'
},
{
name: 'kitchen'
},
{
name: 'skinning'
},
{
name: 'throwing'
}
]
}
]
const cat = Vue.component('categories', {
data: function() {
return {
categories: categories // in real life, this data is shared for example using Vuex
}
},
template: `
<div>
<template v-for="cat in categories">
<router-link :to="'/categories/'+cat.name" :key="cat.name"> {{ cat.name }} </router-link>
</br>
</template>
</div>
`
})
const catView = Vue.component('category-view', {
data: function() {
return {
categories: categories // in real life, this data is shared for example using Vuex
}
},
props: ['categoryId'],
template: `
<div>
<hr>
<router-link :to="parentCategoryPath"> <- Back </router-link>
<div>Params: {{ categoryId }}</div>
<hr>
<template v-if="categoryDefinition && categoryDefinition.childs">
<template v-for="cat in categoryDefinition.childs">
<router-link :to="$route.path+ '/' +cat.name" :key="cat.name"> {{ cat.name }} </router-link>
</br>
</template>
</template>
</div>
`,
computed: {
categoryDefinition() {
let subCategory = this.categories.find(cat => cat.name === this.categoryId[0]);
for (i = 1; i < this.categoryId.length; i++) {
subCategory = subCategory.childs.find(cat => cat.name === this.categoryId[i])
}
return subCategory
},
parentCategoryPath() {
return '/categories/' + this.categoryId.slice(0, -1).join('/')
}
}
})
const router = new VueRouter({
base: '/js',
mode: 'history',
routes: [{
path: '/',
redirect: '/categories',
},
{
path: '/categories',
component: cat,
},
{
path: '/categories/:categoryId+',
component: catView,
props: route => ({
categoryId: route.params.categoryId.split('/')
})
}
]
})
const vm = new Vue({
el: '#app',
router,
data: function() {
return {}
}
})
hr {
border: none;
border-top: 3px double #333;
color: #333;
overflow: visible;
text-align: center;
height: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.5.1/vue-router.min.js" integrity="sha512-c5QVsHf336TmWncPySsNK2ncFiVsPEWOiJGDH/Le/5U6q1hU6F5B7ziAgRwCokxjmu4HZBkfWsQg/D/+X3hFww==" crossorigin="anonymous"></script>
<div id="app">
{{ $route.path }}
<router-view></router-view>
</div>

how to programmatically return to Vue cli's pre-made Home.vue

I'm using Vue CLI 3 and it makes a few routes. One is Home.vue. In my program I am trying to programmaticaly go to different pages. I added the routes I need in router.js but kept the already created routes for Home.vue and About.vue. It works fine until I get to 'Home' and get a warning: [vue-router] Route with name 'Home' does not exist.'
Here is the code:
<template>
<div class='secondItem'>
<h4 v-for="item in menuItems"
#click="bindMe(item)" v-bind:class="{'active':(item === current)}">{{item}}</h4>
</div>
</template>
<script>
export default {
name: 'Header',
data() {
return {
current: '',
menuItems: ['Home', 'About', 'Portfolio', 'Contact'],
}
},
methods: {
bindMe(item) {
this.current = item;
this.$router.push({
path: item
})
}
}
}
<script>
Are you using named routes? In that case you need to use name instead of path:
this.$router.push({
name: item
})
Also, your example can be simplified quite a lot. Try this:
<template>
<div class="secondItem">
<router-link :to="{ name: item }" tag="h4" active-class="active" v-for="item in menuItems" v-bind:key="item">{{item}}</router-link>
</div>
</template>
<script>
export default {
name: 'Header',
data() {
return {
menuItems: ['Home', 'About', 'Portfolio', 'Contact']
}
}
}
<script>