I am using client side routing and have the route name be the object's name. I am linking to the Edit.vue component but if I want to render the age in that Edit component, how do I get that passed in? I know I have name accessible in the router params but I want the other fields in that object too, such as age.
App.vue
<div v-for="item in items">
<router-link :to="`/edit/${item.name}`"> Edit ${item.name} </router-link>
</div>
data() {
return {
items: [ {name: "Carl", age: 23}, { name: "James", age: 43}]
}
}
then in my router config, I have:
const routes = [
{
path: "/",
name: "Home",
component: Home,
},
{
path: "/edit/:name",
name: "Edit",
component: () =>
import(/* webpackChunkName: "edit" */ "../views/Edit.vue"),
},
];
State management is the keyword, which might help for your further research.
Especially vuex, as the most popular Vue state management library probably makes sense in your case (https://www.npmjs.com/package/vuex). There are tons of tutorials out there.
If you don't want to use a state management library, you can implement a simple version of it on your own by saving the data in the localstorage or in the cookies. Or - if it's just about the age, you also could add it to the query params.
There is also a pretty well described SO answer for a similar question: Vue: shared data between different pages
This is not the best way to do it.
You could implement /edit/:name/:age. But what happens if you access the URL /edit/Carl/999?
You should fetch the data, such as name and age, by a unique user id instead: edit/:userid.
Related
I am using Vue JS 3 and Vue Router. I have a company area of the app that uses a dynamic companyId parameter in the route. Ex. myapp.com/46/tasks where 46 is the companyId. Everything works fine when I navigate around to the different sub areas of the company area. However, if I am displaying a router link on any page, and that router link depends on the companyId parameter, if I try to navigate anywhere outside of the company area, which does not require the companyId, the reactivity of the router-link throws an error and the navigation does not happen. If I'm located at the route referenced above, and I try to navigate to
<router-link v-if="session.availableAccounts.length > 1" :to="{name: 'selectCompany'}">
{{ session.selectedAccount.name }}
</router-link>
Here is the router-link that throws the error: (however this happens on any page, with any router-link that requires parameters from the existing page and I then try to navigate somewhere without passing in the parameters EVEN THOUGH THE PARAMETER IS NOT NEEDED FOR THE ROUTE I AM TRYING TO GO TO)
<router-link
:to="{
name:'users',
query: {
selected: person.id,
area: 'Info'
}
}">
{{ person.name }}
</router-link>
Here is the portion of my router.js file concerning the 2 routes I am trying to move between.
{
path: '/account',
component: Base,
meta: {
authorization: true
},
children: [
{
name: 'newAccount',
path: 'new',
component: NewAccount,
meta: {
authorization: true,
title: 'New Account'
}
},
{
name: 'selectCompany',
path: 'selectAccount',
component: SelectCompany,
meta: {
authorization: true,
title: 'Select Account'
}
},
{
name: 'createCustomer',
path: 'create',
component: NewCustomerAccount,
meta: {
authorization: true,
title: 'Create Account'
}
}
]
},
{
path: '/:companyId',
component: Base,
meta: {
authorization: true,
nav: 'account'
},
children: [
{
name: 'home',
path: 'tasks',
alias: '',
component: TaskManager,
meta: {
title: 'My Tasks'
},
},
...
]
}
This happens no matter what method I use to cause navigating, whether I use a router-link or whether I call router.push() in code. However the error always comes from a router-link. If I hide all router-links on the page the navigation works flawlessly. I tried to recreate this on a smaller scale app and I can't seem to make it happen, which means I am doing something wrong but I can't figure it out. I also can't find any similar issues here, which is typically a good indicator that I'm doing something wrong. There is definitely a work-around, where I can store that companyId in a Vuex store and pass it around in the route, but why should I have to pass in a parameter that is not actually in the route?! I really don't want to go down that route (pun intended) unless I absolutely have to. And I first ran into this problem with a child route of the company which needs a projectId parameter. I had the same issue when navigating away from /[:companyId]/[:projectId]/anywhere to /[:companyId]/anywhere IF and only if there is a router-link displayed on the page that relies on [:projectId], and in that situation I was actually relying on whether or not projectId existed within the route params to control a navigation menu. I developed a work around for that behavior but otherwise passing the projectId into the router push to keep the error from happening would have stopped my nav menu from updating correctly.
Is the problem that I do not explicitly define the dynamic route in the parameter? It seems like explicitly defining it would solve my problem but it also requires me to store that somewhere, effectively duplicating the data. I would rather have the id defined in one place (the route) rather than storing it in the store and the route and having to worry about keeping them in sync with each other. Is there no other way?
Any help is appreciated. Thanks.
As is normally the case when I ask a question I discover the answer while asking it. Just posting in case anyone else runs into this same issue. The solution is just to make sure that you explicitly provide the dynamic param when you declare the router-link. Not sure if I like that it lets you create the link without a warning that the required param has not been declared (while there is a warning if vue-router can't resolve the route).
My revised router-link:
<router-link
:to="{
name:'users',
params: {
companyId: route.params.companyId
},
query: {
selected: person.id,
area: 'Info'
}
}">
{{ person.name }}
</router-link>
Hi beautiful Vuejs developers out there!
I have a little problem with routing many Vue components/pages dynamically. In this scenario I am using nested routes to have a couple of routes for my layout components and hundreds of child routes for my pages and as you can imagine I'll have to type many child routes statically or manually, and then add more when I need more child routes in the future code changes but I need a solution to simplify/solve this problem with more efficient/better way like adding those routes from what user types after the layout in the url... here is my example code code:
const routes: RouteRecordRaw[] = [
{
{
path: '/student',
component: () => import('layouts/StudentLayout.vue'),
children: [
{
path: 'dashboard',
component: () => import('pages/student/Dashboard.vue'),
},
{
path: 'profile',
component: () => import('pages/student/Profile.vue'),
},
],
},
}
As you see in this code I have a layout named Student and it has two children but I'll have to type manually hundreds of child routes for this layout and other layouts is there any way to dynamically set up those routes with what users enter after the layout name like /student/dashboard or /layout/page and match it with a component name? I mean like params in Angular, can I use the param value itself inside the router to say?
{
path: ':pagename',
component: (pagename) => import('pages/student/' + pagename + '.vue'),
},
let me know if there is an efficient way to solve this problem.
Thanks in advance!
I would, personally, not use this, or advise such an approach, nor have I done it, but this idea came to me when I read your question:
My best guess would be to have a handler component which renders a component dynamically based on a route parameter (say you have /:subpage as a child to /student and the handler component is set to that route), and an exception handler around that to show a 404 page when the user types in an inexistent/unsupported route.
For example, I would dynamically import the component by the route parameter into a predefined let (e.g. let SubpageComponent; outside the try catch block), have a try catch block around the dynamic import assignment for the respective error where catch would set the variable to a 404 page. Then I would add the SubpageComponent into the data() of the component doing the rendering of the route.
Edit
I've written out come code that, maybe, makes sense.
It's based on https://v2.vuejs.org/v2/guide/components.html#Dynamic-Components
your routes definition, changed
const routes: RouteRecordRaw[] = [
{
path: '/student',
component: () => import('layouts/StudentLayout.vue'),
children: [
{
path: '/:subpage',
component: () => import('pages/student/SubpageRenderer.vue'),
props: true,
},
],
},
]
SubpageRenderer.vue
<script>
export default {
props: ['subpage'],
data() {
return {
currentSubpage: () => import(`./${subpage}.vue`)
}
}
}
</script>
<template>
<component :is="currentSubpage"></component>
</template>
Instead of using the currentSubpage import, you can also use the subpage route prop to bind :is if subpage is the name of a registered component.
Since this would get only "dashboard" from the route, you'd need some namespacing, like "student-dashboard" with the help of template literals. You could make currentSubpage into a template literal that creates the student-${subpage} name.
I'd probably recommend importing the options object of the component designated by the subpage route parameter instead of registering all the components - if you're registering them, you might as well use vue-router the usual way :)
Also, I only think this could work! It should be tested out, and perhaps casing should be kept in mind, and maybe the Layout suffix as well (subpage will probably be all lowercase, and you'll probably have the components named in PascalCase). After uppercasing the first letter, this could also obviously lead to both /student/Dashboard and /student/dashboard being valid routes
I'm still fairly new to Vue, and trying to implement lazy loaded routes on a project that uses class style components. Currently the components are defined for the routes using Webpack's dynamic import like so:
{
path: '/dashboard',
name: 'dashboard',
component: function() {
return import(
/* webpackChunkName: "dashboard" */ '../components/content-views/content-main/ContentDashboard.vue'
);
},
},
But this doesn't seem to be working, as loading the app with an empty cache downloads all of the chunks up front, resulting in an enormous app file. Reading the documentation, it looks like I need to define the class components as async by returning a Promise which resolves with the component. However, I'm honestly not sure if that's possible with a component which is a class definition, as opposed to a typical object-based one. The vue-class-component documentation doesn't mention this, but I'm wondering if there's some kind of alternative syntax for achieving this, or if I'm missing something else.
Any assistance appreciated!
This is how you can use lazy routing in vuejs
path: "/",
name: "index",
component: () =>
import("../views/Index.vue")
just as MaBbKhawaja said,
path: "/",
name: "index",
component: () =>
import("../views/Index.vue")
you can also assign chunkName like this
path: "/",
name: "index",
component: () =>
import(/* webpackChunkName: "Home" */ "../views/Index.vue")
The docs gives a better explanation
I have list of users which I output in Home vue component. Every item in the list is coming from vuex and has it's own details. When I click any of this contacts list items vue-router takes me to route /contact/that-item-id for example contact/4536475. Now, when I am on that page for specific contact list item and refresh my browser vue app breaks, in other words I don't have access to that specific item object properties anymore.
Here is the code of my router
export default new Router({
routes: [
{
path: "/",
name: "Home",
component: Home
},
{
path: "/contact/:id",
name: "ContactDetails",
props: true,
component: ContactDetails
I am setting props property to true so I can pass it as params to contact item details component as so:
<router-link
class="view-more-btn"
:to="{ name: 'ContactDetails', params: { id: contact.id }}"
>VIEW DETAILS</router-link>
and at last I am passing that Id to my getters method in vuex to get details for clicked item as this:
export default {
props: ["id"],
computed: {
contact() {
return this.$store.getters.getContactDetails(this.id);
}
}
Where did I go wrong, why I can't refresh my contact item detail page and still preserve state I am using.
I am new to vue so please forgive me if I am not making sence. And ofcourse any help is welcomed, thanks in advance
The problem is probably, that you're referencing a named route and passing in the params by hand. This won't change the actual route displayed in your browsers address bar and only show the root path (/contact/ in your example I presume). Therefore when you refresh the passed in params/props simply don't exist anymore.
What you need to do instead is use a <router-link :to="'/contact/'+contact.id"> or <router-link :to="`/contact/${contact.id}`"">.
This should affect the URL in your browsers address bar to include the /contact/someID123 which will then also make the ID available on refresh.
I'm try to pass data between Vuejs views with vue-router.
//View1.vue
route: {
data: function (transition) {
transition.next({
message: "this is it!!"
});
}
}
I call next wiew with a click action button with:
//View1.vue
methods:{
showResult: function(){
this.$router.go('/View2');
}
}
but the data are not filled in the next view:
//View2.vue
<template>
<p>Message: {{ message }}</p>
</template>
Does somebody knows what's wrong with my usage of vue-router? I don't think I need to pass through services for this, right?
Working examples on jsfiddle (or jsbin, etc) are welcome :D
If View2 is a child component you can pass it using props:
//View1.vue
<view2-component :passedData='message'></view2-component>
Alternatively, I believe if you set data on the $route object from View1, since that object is shared between all vue instances, I believe it will be available application-wide.
//View1.vue
this.$router.myProps.message = message
But arguably the better way to share data is use a POJO - plain old javascript object and bind it to both views. To do this you typically need a shared state object and you can if you wish use Vuex for this although it is a little more complicated than a POJO.
I know this has already been answered, but if someone is here looking for a way to pass data to a route from a router, I use Meta Data.
Not sure if this is what the questioner meant or not but I think it is?
I personally prefer this to props just because I am more used to using it.
It allows for data to be easily passed and received without having to modify children.
Anyway here is a snippit and link!
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Homepage',
meta: {
logo:{
"/imgs/Normal-Logo.png"
}
}
},
{
path: '/admin',
name: 'Admin',
meta: {
logo:{
"/imgs/Admin-Logo.png"
}
}
},
]
})
In any children who want to use vars:
<logo :src="this.$route.meta.logo"/>
Ref:
https://router.vuejs.org/guide/advanced/meta.html