router-link-active class doesn’t work with different parameters values (Vue Router 4) - vue.js

Hello everyone… I’m latin so my english is not very good looking.
I have this <router-link> component in my custom Navbar component.
<router-link :to="{ name: 'blog', params: { currentPage: 1 } }">Blog</router-link>
And this is my route definition:
{
path: "/blog/:currentPage",
name: "blog",
component: () => import(/* webpackChunkName: "blog" */ "#/views/Blog.vue"),
props(route){
const props = { ...route.params }
props.currentPage = parseInt(props.currentPage, 10)
return props
}
}
I have pagination component inside my Blog view.
<button
v-for="page in numberOfPages"
:key="page"
#click="$router.push({ name: 'blog', params: { currentPage: page } })"
:disabled="page == currentPage">
{{ page }}
</button>
I’m switching the page (ie the currentPage route parameter) from there but router-link-active class is only added to <router-link> with currentPage equal to 1 and none other, how can I keep active this <router-link> regardless the value of currentPage route parameter ? My pagination system must to be dynamic, I can't define a new child route for each page because don’t know how many pages will be.
This problem didn't exist in Vue Router 3 but I’m using Vue Router 4.0.3.
I tried to explaine my issue as well as I could.
Can anybody help me please…

Related

Pass data into router-view to conditionally redirect - Vue Router

I'm wanting to conditionally redirect to a page based on a user's settings.
I have my app where I've passed the user's setting:
<div id="app">
{{ $defaultStartingPage }} <!-- 'search-page' -->
<router-view></router-view>
</div>
I'd like to pass the $defaultStartingPage into my router-view and then handle it there, something like <router-view default-starting-page="{{ $defaultStartingPage }}"> but so far I haven't been able to.
I was able to set the variable to the window in my app.js file and then do this, but it's not reactive and it doesn't feel right.
export default {
routes: [
{
path: '/',
name: 'home',
redirect: () => {
if (window.defaultStartingPage) {
switch (window.defaultStartingPage) {
case 'service-appointments':
return { name: 'services-appointments' };
}
}
return { name: 'services-repairs' };
},
}
]
}
Is there a way to pass attributes to router-view and then access them when returning views? Or maybe a better way to do this?
Thanks!

Vue 3 Composition API vue-router 4 breadcrumbs?

I am trying to create a breadcrumb component.
I made this before with Vue 2 but couldn't manage to do again with Vue 3 as some things have changed and there aren't any guides on how.
I made a very simple route and added meta:
{
path: "/:serviceId?/app-showcase",
name: "AppShowcase",
component: () => import("#/pages/AppShowcase.vue"),
beforeEnter: authGuard,
meta: {
breadcrumb: "App Showcase", // For breadcrumbs in navbar
},
},
Want to have something like this:
Home / Services / fk39f / App Showcase
"fk39f" is a route param.
I was able to get the current route meta by:
<script>
...
const router = useRouter();
const route = router;
// Also getting some route params:
let serviceId = Number(route.currentRoute.value.params.serviceId);
</script>
<template>
<div class="bread-crumbs">
{{ router.currentRoute.value.meta.breadcrumb }}
</div>
...
</template>
Also user should be able to click to the breadcrumbs to go to that page. I tried some solutions like this but couldn't do it.
I couldn't find and solutions after searching for 2 hours.
If I can do this, I was also thinking of making a Vue 3 breadcrumbs library.
How can I achieve this?
Thanks!

Where should route meta data be loaded in a Vue app?

I'm in the process of setting up a VueJs SPA. I'm using vue-router and I'm trying to find the best solution to the following problem. I have a series of routes. Each of which needs to call an API to get the meta data for the given ID.
/industry/:id/overview
/industry/:id/top-stories
/industry/:id/top-tweets
/brand/:id/overview
/brand/:id/top-stories
/brand/:id/top-tweets
I've been looking at using created or beforeRouteEnter/beforeRouteUpdate and I'm a bit lost. Ideally, I would only fetch new data when a new /industry/:id is reached, not when navigating between pages within the same ID. Also, I'd like to avoid having to define the fetch to grab data in every page component. Also don't want to over complicate this, so my question is, Is there a standard method for tackling this issue?
Clarification:
When I say meta here, I mean data returned from an API about the given industry or brand which I pull using the ID in the route. The api call includes the name of the industry/brand which I want to have on page as soon as the page is presented to the user.
I have something similar. I tackle this using the following approach:
I use the same component for all /industry/:id Vue likes to reuse components wherever it can so if two routes (for example /industry/:id/overview and /industry/:id/top-stories) are using the same component it will stay the same.
What does change, however, is the route meta. So if you add a page key to the meta object in the route objects, and probably add a computed property called page that return this.$route.meta.page, you can use v-if attributes to conditionally render any component. So you might have something like <div v-if="page === 'overview'"></div><div v-else-if="page==='top-stories'"></div>
What this allows you to do is fetch all the data from the API during created or mounted lifecycle and store it as the state. Since the route change doesn't reload the component the state stays the same.
Here is a code example
// router.js
const Project = () =>
import(/* webpackChunkName: "projects" */ "./views/projects/_id");
export default new Router({
mode: "history",
routes: [
{
path: "/projects/:project_id/views",
name: "ViewProject",
component: Project,
meta: {
page: "views",
}
},
{
path: "/projects/:project_id/export",
name: "ExportProject",
component: Project,
meta: {
page: "exports"
}
},
{
path: "/projects/:project_id/recommendations",
name: "ProjectRecommendations",
component: Project,
meta: {
page: "recommendations"
}
},
]
});
And here is the template
<template>
<div v-if="project">
<h1>{{ project.name }}</h1>
<router-link :to="/project/someid/views">Views</router-link>
<router-link :to="/project/someid/exports">Exports</router-link>
<router-link :to="/project/someid/recommendations">Recommendations</router-link>
<ul v-if="page==='views">
<li v-for="(view, i) in project.views" :key="i">{{ views }}</div>
</ul>
<ul v-else-if="page==='exports">
<li v-for="(export, i) in project.exports" :key="i">{{ export }}</div>
</ul>
<ul v-else-if="page==='recommendations">
<li v-for="(recommendation, i) in project.recommendations" :key="i">{{ recommendation }}</div>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
project: null
}
},
computed: {
page() {
return this.$route.meta.page;
}
},
mounted() {
this.getProject()
},
methods: {
getProject() {
axios
.get(`/projects/someid`)
.then(res => this.project = res.data)
}
}
}
</script>

Dynamic Vue Router

I am researching whether a vue router is the best approach for the following scenario:
I have a page containing 'n' number of divs. Each of the divs have different content inside them. When a user clicks on a button in the div, I would like the div to open in a separate browser window (including its contents).
Can a route name/component be created on the fly to route to? Since I have 'n' number of divs, that are created dynamically, I cannot hard-code name/components for each one
<router-link :to="{ name: 'fooRoute'}" target="_blank">
Link Text
</router-link>
I want to avoid the same component instance being used (via route with params) since I may want multiple divs to be open at the same time (each one in their own browser window)
If the link is opening in a separate window, it makes no sense to use a <router-link> component as the application will load from scratch in any case. You can use an anchor element instead and generate the href property dynamically for each div.
To answer your questions:
A route name cannot be created dynamically since all routes must be defined at the beginning, when the app (along with router) is being initialized. That said, you can have a dynamic route and then dynamically generate different paths that will be matched by that route.
There is no way for the same component instance to be reused if it's running in a separate browser window/tab.
It is possible to create dynamic router name.
profileList.vue
<template>
<main>
<b-container>
<b-card
v-for="username in ['a', 'b']"
:key="username"
>
<b-link :to="{ name: profileType + 'Profile', params: { [profileType + 'name']: username }}">Details</b-link>
</b-container>
</main>
</template>
<script>
export default {
name: 'profileList',
data () {
return {
profileType: ''
}
},
watch: {
// Call again the method if the route changes.
'$route': function () {
this.whatPageLoaded()
}
},
created () {
this.whatPageLoaded()
},
methods: {
whatPageLoaded () {
this.profileType = this.$route.path // /user or /place
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
</style>
b-container, b-card, b-link are taken from bootstrap-vue, so you can freely change it.
router.js
const router = new Router({
mode: 'hash',
base: process.env.BASE_URL,
linkExactActiveClass: 'active',
routes: [
// USERS
{
path: '/user/:username',
name: userProfile,
component: userProfile
},
{
path: '/user',
name: 'userList',
component: profileList
},
// PLACES
{
path: '/place/:placename',
name: placeProfile,
component: placeProfile
},
{
path: '/place',
name: 'placeList',
component: ProfileList
}
]
})

How does Vue router-link get its parameters?

I have vue router config with routes like this:
{
path: '/:language/:url/filter/',
name: 'search-filter',
component: SearchFilter,
meta: { removeScroll: true }
}
{
path: '/:language/:url/map/',
name: 'search-map',
component: SearchMap,
meta: { removeScroll: true }
}
Whenever I place a router-link with that component like so:
<router-link :to="{ name: 'search-map' }">
<svg-inline name="beacon-circle"></svg-inline>
{{ trans.hotel.show_map }}
</router-link>
It generates a full route to the named route of search-map. Now I have not manually passed in parameters to the <router-link>. It seem to grab the route parameters from the current component to generate the route parameters for the named route url.
I can not find anything about this in the Vue.js documentation about the fact that this is being done automatically.
If I inspect the router-link component with the Vue devtools it does have a props object which contains a to object which holds the parameters. I can't seem to find any documentation on this though.