Nested routes don't follow the defined pattern. VUEjs - vue.js

I'm facing a new issue with nested routes. I've 2 levels of nested routes, and they're not working correctly.
Here are the routes object:
import Login from './components/auth/Login.vue';
import Dashboard from './components/dashboard/Dashboard.vue';
import Signup from './components/auth/Signup.vue';
import Home from './components/shared/Home.vue';
import ProductsHome from './components/dashboard/Products/ProductsHome.vue';
import ProductOverview from './components/dashboard/Products/ProductsOverview.vue';
import CreateProduct from './components/dashboard/Products/CreateProduct.vue';
import CreateCategory from './components/dashboard/Category/CreateCategory.vue';
import EditCategory from './components/dashboard/Category/EditCategory.vue';
import {store} from './store/store.js';
export const routes = [
{path: '/', component: Home},
{ path: '/login', component: Login },
{ path: '/registrarse', component: Signup },
{
path: '/dashboard',
component: Dashboard,
name: 'dashboard',
beforeEnter: (to, from, next) => {
if(to.name === 'dashboard') {
if(store.state.User.credentials.tokenId === null) {
next('/');
//TODO, Hacerlo global y verificar que el dashboard y sus hijos no accedan.
} else {
next();
}
}
next();
},
children: [
{
path: 'productosHome',
component: ProductsHome,
children: [
{
path: '',
component: ProductOverview
},
{
path: 'crearProducto',
component: CreateProduct
},
{
path: 'crearCategoria',
component: CreateCategory
},
{
path: 'editarCategorias',
component: EditCategory
}
]
}
]
}
];
The thing is with the dashboard. When I enter the dashboard or any of its sub-routes (with its router-link component) they don't follow the proper URL path. For example: If a visit the 'productosHome' the URL it's just '/productosHome' and not '/dashboard/productosHome. This same problem applies for every productosHome's child route.
Now, let me show to you my templates:
Dashboard.vue
<template>
<div>
<div class="container is-fluid has-background-light">
<h1 class="title has-text-centered pt-3">Dashboard</h1>
</div>
<section class="section py-3 has-background-light prueba section-dashboard">
<div class="container is-fluid remove-padding dashboard">
<aside class="nav-aside has-background-white">
<div>
<!--El anchor sera nuestro router-link-->
<!-- aside-link-active -->
<a href="#" class="aside-link">
<span class="icon">
<i class="fas fa-users"></i>
</span>
<span class="aside-link-text">Clientes</span>
</a>
</div>
<div>
<router-link class="aside-link"
active-class="aside-link-active"
to="productosHome">
<span class="icon">
<i class="fas fa-tags"></i>
</span>
<span class="aside-link-text">Productos</span>
</router-link>
</div>
<div>
<a href="#" class="aside-link">
<span class="icon">
<i class="fas fa-boxes"></i>
</span>
<span class="aside-link-text">
Pedidos
</span>
</a>
</div>
</aside>
<div class="main-content has-background-white">
<router-view></router-view>
</div>
</div>
</section>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
.aside-link.aside-link-active:hover {
color: white;
}
</style>
ProductsHome.vue
<template>
<div>
<div class="tabs is-medium pt-2 mb-0">
<ul>
<!-- is-active -->
<router-link to="crearProducto"
active-class="is-active"
tag="li">
<a>Crear</a>
</router-link>
<li><a>Editar</a></li>
<li><a>Buscar</a></li>
<router-link to="crearCategoria"
active-class="is-active"
tag="li">
<a>| Crear categorΓ­a</a>
</router-link>
<router-link to="editarCategorias"
active-class="is-active"
tag="li">
<a>Editar categoria</a>
</router-link>
</ul>
</div>
<div class="main-content__content block p-2">
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
Note that Products Home also have children.
Also, I'm debugging routes with the famous Vue plugin and see what says:
'/' is marked has active, Is that correct?
I'm confused :D

The routes file is correct. The issue is with the router link on both files. there are 2 ways you can define router-link>to.
Absolute / Relative Path.
Absolute Path(From any file)
<router-link to="/dashboard/productosHome/">Products Home</router-link>
Relative Path(From dashboard page)
<router-link to="productosHome">Products Home</router-link>
Route object. (From any file)
<router-link :to="{ path: `/dashboard/productosHome/`}">Products Home</router-link>
No 2 gives you a bit more control. you can now name the route and use them. Like you did for dashboard main route. name: 'dashboard',. Now you can name the subroute.
{
path: 'crearProducto',
component: CreateProduct,
name: 'crearProducto'
},
router link will be
<router-link :to="{ name: 'crearProducto'}">Crear Producto</router-link>
Check Documentation for more https://router.vuejs.org/api/#to

When declaring paths in the to attribute of router-link, you need to define the full path including the root "/". E.g.: "/dashboard/productosHome"

Related

Vue router-link doesn't take the page to the layout containing the desired RouterView

I am using vue router and when I use router-link it is not putting my page in the desired position
I'm using a Vite plugin with vue-router in vue 3 to navigate my cms page, but when I set the to="/detail" attribute, they still show all the components, but on this test page I want to set it is a child page with detail properties with id of previous so in parent page i used **<RouterLink
:to="{ name: 'DetailTemplate', params: { id: record._id } }"
See Detail** but when it jumps to the detail page, it no longer has the 2 Nava components above and the menu list on the right
Here is the code in rourouter.js:
import { setupLayouts } from 'virtual:generated-layouts'
import { createRouter, createWebHistory } from 'vue-router'
import routes from '~pages'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [...setupLayouts(routes),
{
path: '/detail/:id', name: 'DetailTemplate', component: () => import('../pages/test.vue')
}
],
scrollBehavior() {
return { top: 0 }
},
})
export default router
And I have a default layout page that looks like this:
component/defaulLayout.vue
<script lang="ts" setup>
import { VerticalNavLayout } from '#layouts'
import DrawerContent from './DrawerContent.vue'
// Components
import Footer from '#/layouts/components/Footer.vue'
</script>
<template>
<VerticalNavLayout>
<!-- πŸ‘‰ navbar -->
<template #navbar>
<VSpacer />
<a
href="https://github.com/themeselection/materio-vuetify-vuejs-admin-template-free"
target="_blank"
rel="noopener noreferrer"
style="color: inherit"
>
</a>
</template>
<!-- πŸ‘‰ Drawer content -->
<template #navigation-drawer-content>
<DrawerContent />
</template>
<!-- πŸ‘‰ Pages -->
<div class="layout-page-content">
<RouterView />
</div>
<!-- πŸ‘‰ Footer -->
<template #footer>
<Footer />
</template>
</VerticalNavLayout>
</template>
This is the parent page containing the overview information
pages/templates.vue
<template>
<div class="show-template">
<a-table
:columns="columns"
:data-source="data"
:pagination="false"
:loading="loadingTable"
bordered
>
<template #bodyCell="{ column, text, record }">
<template v-if="column.key === 'title'">
<a-image
:src="record.image"
width="66px"
height="66px"
/>
<RouterLink tag="a" :to="{ name: 'DetailTemplate', params: { id: record._id } }">{{ text }} See Detail</RouterLink> /<---/
</template>
<template v-if="column.dataIndex === 'fullname'">
<a #click="showListByUser(record.user)">{{ text }}</a>
</template>
<template v-if="column.dataIndex === 'address'">
<a>{{ record.address }}</a>
</template>
</template>
</a-table>
</div>
...
<template>
And here is the App.vue page
<script setup lang="ts">
</script>
<template>
<VApp>
<VLayout class="layout-wrapper layout-nav-type-vertical">
<RouterView />
</VLayout>
</VApp>
<notifications position="top center" />
</template>
In this project I am using the cms outsource Materio page so I added a menu bar component on the right side of the page as follows:
DrawerContent.vue
<template>
<!-- πŸ‘‰ Nav header -->
<div class="nav-header">
<RouterLink
to="/"
class="app-logo d-flex align-center gap-x-3 app-title-wrapper"
>
<!-- ℹ️ You can also use img tag or VImg here -->
<img style="height: 50px" src="../../assets/logogostream.png" alt="">
<Transition name="vertical-nav-app-title">
<h1 class="font-weight-semibold leading-normal text-xl text-uppercase">
GoGame
</h1>
</Transition>
</RouterLink>
</div>
<!-- πŸ‘‰ Nav items -->
<ul>
<VerticalNavLink
:item="{
title: 'Dashboard',
to: 'index',
icon: { icon: 'mdi-home-outline' }
}"
/>
<VerticalNavLink
:item="{
title: 'Account Settings',
to: 'account-settings',
icon: { icon: 'mdi-account-cog-outline' }
}"
/>
<!-- πŸ‘‰ Pages -->
<VerticalNavSectionTitle :item="{ heading: 'Pages' }" />
<VerticalNavLink
:item="{
title: 'Templates',
to: 'templates',
// target: '_blank',
icon: { icon: 'mdi-table' }
}"
/>
<!-- πŸ‘‰ User Interface -->
<VerticalNavSectionTitle :item="{ heading: 'User Interface' }" />
<VerticalNavLink
:item="{
title: 'Icons',
to: 'icons',
icon: { icon: 'mdi-eye-outline' }
}"
/>
</ul>
There are two problems with me:
First, when I click on See Detail it goes to detail page but it seems that it doesn't go to RouterView in defaultLayout page so it doesn't show component navar and right menu list.
Second is that i want when i go to the detail page of the template i want the right menu bar titled "templates" to still be active(css), but now i see it only active when i go to the correct template page and i go to the detail page it doesn't match. Is there any solution for me? Thanks

Error : vue Maximum call stack size exceeded

i'm building an app, i tried to do router for login page but it give me this error :
vue.runtime.esm.js?2b0e:4484 Uncaught RangeError: Maximum call stack size exceeded, is there anything i did wrong
thank you for your help hopefully u can give me a hint on how to fix it
this is the Login Components
<template>
<div class="hello">
Login
</div>
</template>
<script>
export default {
name: '',
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
Home Components
<template>
<div class="hello">
<header class="globalNav noDropdownTransition">
<div class="container-lg">
<ul class="navRoot">
<li class="navSection logo">
<a class="rootLink item-home colorize" href="/"><h1>Charity Finder</h1></a>
</li>
<li class="navSection primary">
<a class="rootLink item-products hasDropdown colorize" data-dropdown="products">
Products
</a>
<a class="rootLink item-developers hasDropdown colorize" data-dropdown="developers">
Developers
</a>
<a class="rootLink item-company hasDropdown colorize" data-dropdown="company">
Company
</a>
</li>
<li class="navSection secondary">
<a class="rootLink item-support colorize" href="">
Support
</a>
<router-link class="rootLink item-dashboard colorize" to="/login"> Sign in</router-link>
</li>
</ul>
</div>
</header>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
This the router Router
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Login from '../views/Login.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/login',
name: 'login',
component: Login
}
]
const router = new VueRouter({
routes
})
export default router

Get the value for a query parameter re-actively

Hello I want to pass the value of my reactive data to the query parameter, but I don't know how?
<template>
<div id="app">
<div id="nav">
<router-link :to="{ name: 'HomeRoute', query: { lang: language } }">{{
$t("home")
}}</router-link>
|
<router-link to="/about">About</router-link>
</div>
<router-view />
</div>
</template>
<script>
import i18n from "./i18n";
export default {
data() {
return {
language: i18n.locale,
};
},
</script>
In this example, I want to set the value of the query parameter (lang) to be the same as i18n.local, which is store to a variable called language. I really appreciate if someone can help me with it.
In your data you can make a route object and simply pass it to your :to property
<template>
<div id="app">
<div id="nav">
<router-link :to="home_route">{{
$t("home")
}}</router-link>
|
<router-link to="/about">About</router-link>
</div>
<router-view />
</div>
</template>
<script>
import i18n from "./i18n";
export default {
data() {
return {
home_route : { name: 'HomeRoute', query: { lang: i18n.locale } }
};
},
</script>

Bulma navbar and VueJS router active link

I've started using Bulma 0.7.1 and VueJs 2.5.17. Now, I'm using Vue router component and I'd like to make the buttons in the navigation bar to be set as active whenever I'm on the "page" represented by the link.
My code is the following
<template>
<div id="app">
<nav class="navbar" role="navigation" aria-label="main navigation" id="nav">
<div class="container">
<div id="navMenu" class="navbar-menu">
<div class="navbar-end">
<a class="navbar-item is-active">
<router-link to="/" exact>Home</router-link>
</a>
<a class="navbar-item">
<router-link to="/about" exact>About</router-link>
</a>
<a class="navbar-item">
<router-link to="/project" exact>Project</router-link>
</a>
</div>
<div class="navbar-end">
</div>
</div>
</div>
</nav>
<router-view/>
</div>
</template>
I know that router component uses class router-link-active to mark the active link. But Bulma probably requires the is-active class applied to the current button.
How should I automate this? I've read that probably I should bind the class is-active to the router-link-active, but I tried:
let routes = ...
new VueRouter({
mode: "history",
routes,
linkActiveClass: "is-active"
});
And did not worked.
Any hint is really appreciated.
You are on the right track and are right, 'is-active' is the answer. In router add.
export const router = new VueRouter({
mode: 'history',
routes,
linkActiveClass: 'is-active'
})
And construct your HTML like.
<nav class="navbar is-white">
<div class="container">
<div id="navMenu"
class="navbar-menu">
<div class="navbar-start">
<router-link :to="{ name: 'templateInfo' }"
class="navbar-item">Template info</router-link>
<router-link :to="{ name: 'thirdpartylibraries' }"
class="navbar-item">Third party libraries</router-link>
</div>
</div>
</div>
</nav>
This works for me so I guess there's some issue with the order of your div's or classes.
Check Bulma Guide, is-active is one modifier, you have to use it together with bulma element.
Most Bulma elements have alternative styles. To apply them, you only
need to append one of the modifier classes. They all start with is- or
has-.
So change the configuration to like linkActiveClass: 'tag is-active' it will work well.
Like below demo which uses tag (you can choose others like box, button etc):
let UserView = Vue.component('user', {
template: '<div>I am User</div>'
})
let AdminView = Vue.component('admin', {
template: '<div>I am Admin</div>'
})
const router = new VueRouter({
linkActiveClass: 'tag is-active',
routes: [
{
path: '/Admin',
name: 'Admin',
component: AdminView
},
{
path: '/User',
name: 'User',
component: UserView
}
]
})
Vue.use(VueRouter)
app = new Vue({
el: "#app",
router
})
.loading {
background-color:red;
font-weight:bold;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css" rel="stylesheet"/>
<script src="https://unpkg.com/vue#2.5.16/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<h2>Test Vue Router</h2>
<router-link to="Admin">Admin</router-link>
<router-link to="User">User</router-link>
<router-view></router-view>
</div>

Laravel Vuejs2 missing param for named route

I am having a hard time trying to isolate the console error.
My code is as follows:
myside.blade.php has:
<div class="nav-container">
<ul class="nav nav-icons justify-content-center" role="tablist">
<li class="nav-item">
<div>
<router-link class="nav-link text-primary" :to="{ name: 'property', params: { customerId: {{ $property_data[0]->listingId }} }}" #click.native="isVisible = !isVisible">
<i class="nc-icon nc-key-25"></i>
<br> Property
</router-link>
</div>
</li>
<li class="nav-item">
<router-link class="nav-link text-primary" :to="{ name: 'booking' }" #click.native="isVisible = !isVisible">
<i class="nc-icon nc-chart-pie-36"></i>
<br> Bookings
</router-link>
</li>
<li class="nav-item">
<a class="nav-link text-primary" href="" role="tab">
<i class="nc-icon nc-preferences-circle-rotate"></i>
<br> Performance
</a>
</li>
<li class="nav-item">
<a class="nav-link text-primary" href="" role="tab">
<i class="nc-icon nc-money-coins"></i>
<br> Revenue
</a>
</li>
<li class="nav-item">
<a class="nav-link text-primary" href="" role="tab">
<i class="nc-icon nc-layers-3"></i>
<br> Integration
</a>
</li>
</ul>
</div>
<property-page :customer-Id="{{ $property_data[0]->listingId }}" v-if="isVisible"></property-page>
<router-view></router-view>
My routes.js file:
import VueRouter from 'vue-router';
let routes = [
{
path: '/property/:customerId',
name: 'property',
component: require('./components/PropertyPage'),
props: true
},
{
path: '/booking',
name: 'booking',
component: require('./components/BookingPage')
}
];
export default new VueRouter({
routes,
linkActiveClass: 'nav-link text-success'
});
my app.js file:
import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
import router from './routes';
import PropertyPage from './components/PropertyPage.vue';
import BookingPage from './components/BookingPage.vue';
new Vue({
el: '#root',
router,
data: {
NavPrimaryClass: 'nav-link text-primary',
NavClass: 'nav-link',
isVisible: true
},
components: {
'property-page': PropertyPage,
'booking-page': BookingPage
}
})
my PropertyPage.vue file:
<template>
<div>
<div class="ajax-loader">
<img src="/loader/ajax-loader.gif" width="300px" v-if="loading" />
</div>
<div v-if="propertyDataCheck">
</div>
</div>
</template>
<script>
import moment from 'moment';
import axios from 'axios';
export default {
props: {
customerId: {
type: Integer,
required: true,
default: 0
}
},
data() {
return {
propertyData: [],
loading: false
}
},
computed: {
propertyDataCheck () {
return this.propertyData.length;
}
},
mounted() {
this.loading = true;
axios.get('/ajax/propertydata/' + this.customerId)
.then(function(response) {
this.propertyData = response.data;
this.loading = false;
}.bind(this))
.catch(function() {
this.loading = false;
}.bind(this));
}
}
</script>
<style>
.ajax-loader {
position: absolute;
left: 40%;
top: 15%;
margin-left: -32px; /* -1 * image width / 2 */
margin-top: -32px; /* -1 * image height / 2 */
}
</style>
The end result, a console error which I have spent hours trying to work out where it is coming from.
Error:
[vue-router] missing param for named route "property": Expected "customer" to be defined
I needed a component to be loaded upon page load (outside of vue-router) which is why I have <property-page :customer-Id="{{ $property_data[0]->listingId }}" v-if="isVisible"></property-page> tags and is bound to a method which will switch upon a router-link click (in case you were wondering).
My understanding of this error is the variable for the first router-link which is generated from a Laravel model DB query {{ $property_data[0]->listingId }} should be checked within a v-if wrapped around the vue-router? I have also done this to no avail.
Any help would be much appreciated!
Believe it or not, you need to use strict kebab-case (all lower case!) html-properties in vue-templates. Change customer-Id to customer-id
<property-page :customer-Id=... // does not get mapped to this.customerId
<property-page :customer-id=... // does get mapped to this.customerId, yay!