VueJS Router-link not linking to the view - javascript

I have a problem with the router link. When I put it in a view, it works very well, I have a clickable link. But when I put a router link in a component, built into a view, then the router link no longer works: I would like "just" to link to the detail of a project.
This work (resources/js/views/HomepageView.vue)
<router-link :to="{ name: 'projects.show', params: { slug: slideshowProject.slug }}">
<a href="#" class="btn-secondary">See
Campaign</a>
</router-link>
This doesn't work (resources/js/components/UserProject.vue)
<router-link :to="{ name: 'projects.show', params: { slug: project.slug }}">
<h4>{‌{ project.title}}</h4>
</router-link>
Script part of the page :
<script>
export default {
name: "user-projects",
data() {
return {
projects: null
}
},
mounted() {
this.getUserProject()
},
methods: {
getUserProject() {
this.$store.dispatch('getUserProjects', {
limit: 2
}).then(response => {
this.projects = response.data.data;
})
}
},
}
</script>
My router.js
import Homepage from '../views/frontend/HomepageView';
import ProjectDetails from '../views/frontend/ProjectDetailsView';
import LoginView from '../views/frontend/LoginView';
import RegisterView from '../views/frontend/RegisterView';
import DashboardIndexView from '../views/dashboard/DashboardIndexView';
export const routes = [
{
path: '',
name: 'homepage',
component: Homepage
},
{
path: '/login',
name: 'frontend-login',
component: LoginView
},
{
path: '/projects/:slug',
name: 'projects.show',
component: ProjectDetails
},
{
path: '/register',
name: 'frontend-register',
component: RegisterView
},
{
path: '/dashboard',
name: 'dashboard-index',
component: DashboardIndexView
}
];
I don't understand where is my mistake :/

You can check slug is not empty before render a router link, like below sample:
<router-link v-if="project.slug" to="{ name: 'projects.show', params: { slug: project.slug }}">
<h4>{‌{ project.title}}</h4>
</router-link>
But I am sure, why slug is empty.

Thanks to Jom, the problem was that my "slug" was empty, and indeed when i look at the console, the warning was there.
[vue-router] missing param for named route "projects.show": Expected "slug" to be defined

Related

Vue3 Redirect with dynamic property

I have this configuration in my router.ts:
{
path: "/admin/operations/job-allocation/:id",
name: "JobAllocation",
component: () =>
import(
"#/views/admin/operations/job-allocation/index.vue"
),
children: [
{
path: "",
redirect:
"/admin/operations/job-allocation/:id/operatives",
},
{
path: "/admin/operations/job-allocation/:id/operatives",
name: "JobAllocationOperatives",
alias: "Operatives",
component: () =>
import("#/views/common/Operatives.vue"),
},
]
}
When I visit the path: /admin/operations/job-allocation/1 I want to go to /admin/operations/job-allocation/1/operatives.
But in this setup it goes to /admin/operations/job-allocation/:id/operatives (the :id as a literal string of ':id' instead of being replaced by the number 1.
I'm hoping to use the router to do this, instead of using a 'mounted' hook to do the redirect at the JobAllocation component.
Is this even possible? I did not find this senario in the official Vue3 Router docs.
Use the object form of redirect to specify the route by name, so that the parameters are automatically passed along:
export default createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
component: HelloWorld
},
{
path: '/admin/operations/job-allocation/:id',
name: 'JobAllocation',
props: true,
component: () => import('#/views/admin/operations/job-allocation/index.vue'),
children: [
{
path: '',
redirect: {
name: 'JobAllocationOperatives', 👈
},
},
{
path: '/admin/operations/job-allocation/:id/operatives',
name: 'JobAllocationOperatives',
alias: 'Operatives',
component: () => import('#/views/common/Operatives.vue')
}
]
}
]
})
demo

Why is my Vue navbar changing the route but not updating the router-view?

I'm using Vue to make a single-page application and I have a navbar and have set up Vue-Router. For some reason, every time after the first time I use the navbar, the route changes but the router-view does not. Here's the code from NavBar.vue:
<template>
<div id="app">
<v-toolbar id="navbar" app color="#330066" dark>
<v-toolbar-side-icon></v-toolbar-side-icon>
<v-toolbar-title id="appname">{{ appname }}</v-toolbar-title>
<v-spacer></v-spacer>
<span :key="item.link" v-for="item in items" class="nav-elt">
<router-link active-class="nav-elt-active" tag="span" :to="item.link">
{{ item.title }}
</router-link>
</span>
</v-toolbar>
</div>
</template>
<script>
export default {
name: "NavBar",
props: {
appname: String,
},
data() {
return {
items: [
{ title: "Home", link: "/" },
{ title: "Search", link: "/search" },
],
};
},
};
</script>
And here's from App.vue:
<template>
<v-app>
<v-main>
<NavBar appname="Newsfacts" />
<router-view />
</v-main>
</v-app>
</template>
<script>
import NavBar from "./components/NavBar";
export default {
name: "App",
components: {
NavBar,
},
data() {
return {};
},
};
</script>
Here's from router/index.js:
import Vue from 'vue';
import Router from 'vue-router';
import Home from '../views/Home.vue';
import Search from '../views/Search.vue';
Vue.use(Router);
export default new Router({
mode: "history",
routes: [
{
path: "/",
name: "Home",
component: Home
},
{
path: "/search",
name: "Search",
component: Search
}
]
});
If you need anything else, the full code is on my github, and a demo is at a netlify site
The link attribute inside the array of items should contain a '/' at the beginning of every route.
So, it should look like this:
data() {
return {
items: [
{ title: "Home", link: "/home" },
{ title: "Search", link: "/search" },
],
};
},
Also, it is probable that the component is not being rendered because you are using <v-btn/> for routing, instead of <router-link/>.
I recommend you use <router-link/> instead of <v-btn/> for navigation in order to support all the features provided by Vue Router like history mode, base, etc.
In case you necessarily need the v-btn, I think you can wrap the <router-link/> inside the button or viceversa.
For more information about Vue Router and <router-link/>, check out this link:
https://router.vuejs.org/api/#router-link
where is your vue router component definitions?
e.g
const FooHome= { template: '<div>Home</div>' }
const Search= { template: '<div>Search</div>' }
const routes = [
{ path: '/', component: Home},
{ path: '/search', component: Search}
]
const router = new VueRouter({
routes
})
const app = new Vue({
router
}).$mount('#app')
Turns out I was returning an empty dictionary in a few data() functions, and that caused the app to break. Thanks to #inked6233 on the Vue Land discord for helping me find that!

Vue router doesn't redirect to welcome page, if 404 page is defined with alias *

I have the following route configuration. I would expect the router to redirect the client to /dashboard when entering the page without any url extension. However, it displays the 404 page. If I comment out alias: '*' for the 404 page (which technically disables it form my understanding), the redirect works as expected.
function configRoutes() {
return [
{
path: '/',
redirect: '/dashboard',
name: 'Home',
component: TheContainer,
children: [
{
path: 'dashboard',
name: 'Dashboard',
component: Dashboard
},
{
path: 'pickingList/:roleID-:roleName/:viewID-:viewName',
name: 'Kommissionierliste',
component: PickingList
},
{
path: 'admin/clients',
name: 'Clients',
component: AdminClients,
meta: {
requiresUserGroup: 'admin'
},
children: [
{
path: ':id-:name',
name: 'Clienteinstellungen',
component: AdminClientSettings,
meta: {}
}
]
},
{
path: 'admin/roles',
name: 'Rollen',
component: AdminRoles,
meta: {
requiresUserGroup: 'admin'
},
children: [
{
path: ':id-:name',
name: 'Rolleneinstellungen',
component: AdminRoleSettings,
meta: {}
}
]
},
{
path: 'login',
name: 'Login',
component: Login
},
{
path: 'admin/viewers',
name: 'Ansichten',
component: AdminViewerRoles,
meta: {
requiresUserGroup: 'admin'
},
children: [
{
path: ':id-:name',
name: 'Ansichtseinstellungen',
component: AdminViewerRoleSettings,
meta: {}
}
]
},
{
path: '404',
name: 'PageNotFound',
component: PageNotFound,
alias: '*',
meta: {
label: 'Seite nicht gefunden'
}
}
]
}
]
}
How can I fix that?
You should move the 404 page up in the tree to be out of any children arrays, remove its alias and instead set its path to be *. The catch-all route should always be last in your list of routes (otherwise it will hide all routes which are listed after it in the array).
Variant 1 - all routes are wrapped by TheContainer
App.vue
<template>
<TheContainer>
<MySidebar slot="sidebar" />
<router-view />
</TheContainer>
</template>
Variant 2 - custom layout in each route
App.vue
<template>
<router-view />
</template>
Route A
<template>
<LayoutA>
<Sidebar slot="side" />
<Toolbar slot="top" />
<!-- content specific to the route -->
</LayoutA>
</template>
Route B
<template>
<LayoutY>
<MyToolbar slot="top" />
<!-- content for this route -->
<MyFooter slot="bottom" />
</LayoutY>
</template>

Vue.js 2 router only loading component from navigation and not from URL

When clicking to view page content from the menu the correct component loads. However, when I go it directly from the URL it doesn't.
This is the master page (which loads the menu):
<template>
<div class="row">
<div class="col-md-3 col-sm-3 col-xs-3">
<router-link to="/new-page" type="button" class="btn btn-primary btn-lg btn-block">New page</router-link>
<div class="list-group sidebar">
<router-link v-for="page in pages" class="list-group-item" :to="'/pages/' + page.slug">{{ page.menu_title }}</router-link>
</div>
</div>
<div class="col-md-9 col-sm-9 col-xs-9">
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
computed: {
pages() {
return this.$store.state.pages
}
},
created() {
this.$http.get('pages').then((response) => {
this.$store.commit('setPages', response.body)
console.log(response)
}, (response) => {
console.log("Error: " + response)
})
}
}
</script>
This is the content which loads a content type depending what page type is clicked. You can use multiple templates which reloads with different data (that part is OK)
<template>
<div>
<div class="loader" v-if="loading">
<div class="bounce1"></div>
<div class="bounce2"></div>
<div class="bounce3"></div>
</div>
<div v-if="!loading">
<vc-gig :content="content" v-if="content.type == 'gig'"></vc-gig>
<vc-news :content="content" v-if="content.type == 'news'"></vc-news>
<vc-home :content="content" v-if="content.type == 'home'"></vc-home>
<vc-image :content="content" v-if="content.type == 'image'"></vc-image>
</div>
</div>
</template>
<script>
import Gig from '../Gig.vue'
import News from '../News.vue'
import Home from '../Home.vue'
export default {
components: {
'vc-gig': Gig,
'vc-news': News,
'vc-home': Home,
},
data() {
return {
loading: true,
content: [],
}
},
created() {
this.getPageData
},
watch: {
'$route': 'getPageData'
},
methods: {
getPageData() {
this.loading = true
this.$http.get('pages/' + this.$route.params.pageSlug).then((response) => {
this.content = response.body
this.loading = false
console.log(response.body)
}, (response) => {
console.log(response)
})
}
}
}
</script>
All components load correctly when clicking the menu (in the first code section) but if I add the URL manually in the browser the page content (second code section) wont load.
Update: Here is my full routes.js file:
import Vue from 'vue'
import VueRouter from 'vue-router'
// Public
import Home from './views/Pages/Home.vue'
// Authentication
import Login from './views/Auth/Login.vue'
import Register from './views/Auth/Register.vue'
import Onboarding from './views/Auth/Onboarding.vue'
import ResetPassword from './views/Auth/ResetPassword.vue'
// Pages & Items
import Pages from './views/Pages/Layout/PageMaster.vue'
import Page from './views/Pages/Layout/PageSinge.vue'
import Item from './views/Pages/Layout/PageItem.vue'
import NewPage from './views/Pages/NewPage.vue'
// Options
import Options from './views/Options/Layout/OptionsMaster.vue'
import Themes from './views/Options/Themes.vue'
import Logo from './views/Options/Logo.vue'
import SocialMediaIcons from './views/Options/SocialMediaIcons.vue'
import WebsiteTitle from './views/Options/WebsiteTitle.vue'
import DomainName from './views/Options/DomainName.vue'
import Meta from './views/Options/Meta.vue'
import AnalyticsWebtools from './views/Options/AnalyticsWebtools.vue'
// My Account
import Account from './views/Account/Layout/AccountMaster.vue'
import Billing from './views/Account/Billing.vue'
import Details from './views/Account/Details.vue'
import Password from './views/Account/Password.vue'
Vue.use(VueRouter)
const Router = new VueRouter({
mode: 'history',
routes: [
{
path: '/login',
name: 'login',
component: Login,
meta: {guest: true}
},
{
path: '/register',
name: 'register',
component: Register,
meta: {guest: true}
},
{
path: '/reset-password',
name: 'reset-password',
component: ResetPassword,
meta: {guest: true}
},
{
path: '/onboarding',
name: 'onboarding',
component: Onboarding
},
{
path: '/',
name: 'home',
redirect: 'pages/home',
component: Home,
meta: {auth: true}
},
{
path: '/new-page',
name: 'newpage',
component: NewPage,
meta: {auth: true}
},
{
path: '/pages',
name: 'pages',
redirect: 'pages/home',
component: Pages,
meta: {auth: true},
children: [
{
path: ':pageSlug',
name: 'page',
component: Page,
},
]
},
{
path: '/pages/:pageSlug/:itemSlug',
name: 'item',
component: Item,
meta: {auth: true}
},
{
path: '/options',
name: 'options',
redirect: 'options/themes',
component: Options,
meta: {auth: true},
children: [
{
path: 'themes',
name: 'themes',
component: Themes
},
{
path: 'logo',
name: 'logo',
component: Logo
},
{
path: 'social-media-icons',
name: 'socialmediaicons',
component: SocialMediaIcons
},
{
path: 'website-title',
name: 'sitetitle',
component: WebsiteTitle
},
{
path: 'domain-name',
name: 'domain',
component: DomainName
},
{
path: 'meta-text-image',
name: 'meta',
component: Meta
},
{
path: 'analytics-webtools',
name: 'tools',
component: AnalyticsWebtools
},
]
},
{
path: '/account',
name: 'account',
component: Account,
meta: {auth: true},
children: [
{
path: 'billing',
name: 'billing',
component: Billing
},
{
path: 'details',
name: 'details',
component: Details
},
{
path: 'password',
name: 'password',
component: Password
},
]
}
]
})
Router.beforeEach(function (to, from, next) {
// User is authenticated
if (to.matched.some(function (record) {
return record.meta.guest
}) && Vue.auth.loggedIn()) {
next({
path: '/pages'
})
} else {
next()
}
// User not authenticated
if (to.matched.some(function (record) {
return record.meta.auth
}) && !Vue.auth.loggedIn()) {
next({
path: '/login'
})
} else {
next()
}
})
export default Router
Simple fix, you are not calling the method you created.
created() {
this.getPageData
},
should be
created() {
this.getPageData()
},
Also perhaps using a linter such as eslint would help avoid these mistakes.
http://eslint.org/
Happy coding!

router-link not rendering links properly

I am trying to iterate over some data to produce my router-links
<router-link v-for="(data, dataKey) in dataObject"
:to="{ params: { dataKey: dataKey }}"
tag="li">
<a>
<span>
{{ dataKey }}
</span>
</a>
</router-link>
This creates the tags with the right strings but doesn't append dataKey to the link when I'm not one of the links I'm trying to build.
dataKey even prints out properly within the <span> </span>
However, when I navigate manually to one of the links, all the params are properly appended.
export const routes = [
{ path: '/', component: Home, beforeEnter: checkAuthentication },
{ path: '/dashboard',
component: Dashboard,
children: [
{
path: '',
component: DashboardHome,
name: 'Dashboard Home'
},
{
path: 'profile',
component: DashboardPhotos,
children: [
{
path: '',
component: DashboardPhotosHome,
name: 'Dashboard Profile Home'
},
{
path: ':dataKey',
component: PhotoViewer,
props: true
}
]
},

Categories

Resources