I am trying to send data from one vue component to another by using props in router. but it is not working. whenever i try to log the props it outputs undefined. code is given below
From where data is sending
Where receiving
in index.js. router setting
None of the code you've posted matches up.
Firstly, the console logging should be just console.log(this.myprops). The point of using props is that you don't need to reference the router itself, e.g. via $router.
Next problem, you're mixing path and params. That isn't allows. See https://router.vuejs.org/guide/essentials/navigation.html. params are for named routes.
I imagine what you're aiming for is something like this:
self.$router.replace({ name: 'DashboardPatient', params: { myprops: authUser.email } })
with router config:
{
path: '/patient',
component: Dash,
children: [
{
path: ':myprops', // <--- Adding myprops to the URL
name: 'DashboardPatient',
component: DashboardPatient,
props: true,
meta: { requiresAuth: true }
}
]
}
Keep in mind that routing is all about building and parsing the URL. So the value of myprops needs to be in the URL somewhere. In my example it comes at the end, so you'll get /patient/user#example.com as the URL. If it weren't in the URL then there'd be no way for the router to populate the prop if the user hit that page directly (or refreshed the page).
To hit the same route using a path instead of a name it'd be something like this:
self.$router.replace({ path: `patient/${encodeURIComponent(authUser.email)}` })
or even just:
self.$router.replace(`patient/${encodeURIComponent(authUser.email)}`)
Personally I'd go with the named route so that the encoding is handled automatically.
If you don't want to put the data in the URL then routing is not the appropriate way to pass it along. You'd need to use an alternative, such as putting it in the Vuex store.
Related
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 have a lot of articles in my app, and the URL are written like this in Vue Router: /article/:id.
I have particular articles I want to "pin" and have easier URLs. For example: /pinned-article, which should point to /article/3274 and /other-pinned-article, pointing to /article/68173.
I though about adding this to my routes, but it doesn't work:
{ path: '/article/3274', component: Article, alias: '/pinned-article' }
I thought about something else, involving another component:
{ path: '/pinned-article/:id', component: PinnedArticle }
The component PinnedArticle silently aliasing the correct article with a command like router.alias in the <script> section, but it apparently doesn't exist.
Is there a way to solve this problem? I thought I could use some answers I read here in Stackvoverflow (for examples when it comes to redirect /me to /user/:id, but it doesn't apply.
Thanks in advance :)
addRoute
You can achieve this with Dynamic Routing, which is not the same as dynamic route matching, i.e. route params.
(This solution works in both Vue 3 and Vue 2 with Vue Router >= 3.5.0)
By using the addRoute method of Vue router, you can create routes at runtime. You can either use a redirect or not, depending on whether you want the url bar to read /article/3274 or /pinned.
Redirect
If you want the url to change from /pinned to /article/3274, use redirect:
methods: {
pinRoute() {
this.$router.addRoute({
path: '/pinned',
name: 'pinned',
redirect: { name: 'article', params: { id: 3274 }}
})
}
}
Access the route like:
this.$router.push('/pinned')
The above example assumes you give your Article route a name: 'article' property so you can redirect to it
Alias
You can keep the URL as /pinned using alias. Normally the alias would go on the existing Article route definition, but that doesn't work well with route params. You can use a "reverse alias" with a new route:
methods: {
pinRoute() {
this.$router.addRoute({
path: '/params/3274',
name: 'pinned',
alias: '/pinned',
component: () => import('#/views/Article.vue') // Article component path
})
}
}
Access the route like:
this.$router.push('/pinned')
Notes:
You'll probably want to pass an id argument to the pinRoute methods rather than hardcode them like in the examples above.
A nice thing about addRoute with either method above is if the route already exists, say, from the last time you called the method, it gets overwritten. So you can use the method as many times as you like to keep changing the destination of /pinned. (The docs in both Vue 2 and Vue 3 say the route definition will get overwritten, though Vue 2 router throws a duplicate route warning.)
Of course the pinned route won't automatically persist between app refreshes, so you'll need to save/load the pinned id (i.e. using localStorage, etc.) and run one of these methods on app load if you want that
i'm using Nuxt
I'm having troubles with passing data from one page to another
I would like programmatically to navigate to other page, and pass some data to other page (in this case its javascript object)
So here is my code so far:
I have a component in which I navigate from:
this.$router.push({ path: 'page/add', props: { basket: 'pie' } });
And here is a component where I would like to get data, its a Nuxt page:
export default {
components: { MyComponent },
props: [
'basket' // this is also empty
],
async asyncData(data) {
console.log(data); // data does not contain basket prop
},
meta: {
breadcrumb: {
path: '/page/add',
},
},
};
</script>
But when I try to acces props, or data or data.router it does not contain basket prop ??
Also, I would not like to use query, or params because they change URL
[1]: https://nuxtjs.org/
You can use localstorage and save you'r data in it:
localStorage.setItem("nameOfItem", Value);
and delete it if you want after you'r done with it:
localStorage.removeItem("nameOfItem");
If you don't want to use query or params, I would check out the vuex store. Its a really cool way of storing global variables and use it in multiple pages.
Vuex store
Navigate to a different location
To navigate to a different URL, use router.push. This method pushes a new entry into the history stack, so when the user clicks the browser back button they will be taken to the previous URL.
The argument can be a string path, or a location descriptor object. Examples:
// literal string path
this.$router.push('/users/eduardo')
// object with path
this.$router.push({ path: '/users/eduardo' })
// named route with params to let the router build the url
this.$router.push({ name: 'user', params: { username: 'eduardo' } })
// with query, resulting in /register?plan=private
this.$router.push({ path: '/register', query: { plan: 'private' } })
// with hash, resulting in /about#team
this.$router.push({ path: '/about', hash: '#team' })
reference:
https://router.vuejs.org/guide/essentials/navigation.html#navigate-to-a-different-location
To navigate to a different URL, use router.push. This method pushes a new entry into the history stack, so when the user clicks the browser back button they will be taken to the previous URL.
What you are trying to accomplish is not conform with the browser (history etc.) or
http protocol (GET/POST).
Also, when using path params and other variables, such will be ignored, as per the documentation.
Note: params are ignored if a path is provided, which is not the case for query, as shown in the example above. Instead, you need to provide the name of the route or manually specify the whole path with any parameter.
Using props here is very likely the wrong approach, as you will never get that data to the component.
I have a use case for needing the id part of a vue route to contain unescaped forward slashes.
My current route looks like this:
{
path: '/browse/:path*',
component: browse,
name: 'browse',
displayName: 'Browse',
meta: { title: 'Browse' },
},
So when a user browses to the above url, the browse component is shown.
However, i want to use the id part of the path (:path*) to contain a nestable fielsystem like path to be consumed by my browse page.
For example the url /browse/project/project1 would take me two levels down in my tree to the project1 item.
Now, the problem i'm running into is that vue router is escaping my ids (path) when navigating programatically, and my url ends up like this: /browse/project%2Fproject1. This is non-ideal and does not look nice to the end user. Also, if the user does browse to /browse/project/project1 manually the app will work correctly and even keep the original encoding in the url bar.
So i could resolve this my making an arbitrary number of child paths and hope that the system never goes over these, but thats not a good way to solve my problem.
I should also clarify that the application will not know anything about the path after /browse as this is generated dynamically by the api that powers the app.
Is there a native way in vue-router to handale this? or should i change up how im doing things.
There is a more elegant solution without workarounds.
Vue router uses path-to-regexp module under the hood and constructions like
const regexp = pathToRegexp('/browse/:path*')
// keys = [{ name: 'browse', delimiter: '/', optional: true, repeat: true }]
https://github.com/pillarjs/path-to-regexp#zero-or-more
const regexp = pathToRegexp('/browse/:path+')
// keys = [{ name: 'browse', delimiter: '/', optional: false, repeat: true }]
https://github.com/pillarjs/path-to-regexp#one-or-more
set repeat flag to true. Any array parameter with repeat flag will be joined with the delimiter (default '/').
So you can pass a splitted array ['project','project1'] instead of 'project/project1' into router.push():
router.push( {name: 'browse', params: {path: ['project','project1']}} );
or
router.push( {name: 'browse', params: {path: 'project/project1'.split('/')}} );
So I managed to 'fix' this with a bit of a hack.
When creating my Vue router instance I am attaching a beforeEach function to replace any outgoing encodings of '/'. This will send the 'correct' URL I am looking for to the client.
const router = new Router({
mode: 'history',
routes,
});
router.beforeEach((to, from, next) => {
// hack to allow for forward slashes in path ids
if (to.fullPath.includes('%2F')) {
next(to.fullPath.replace('%2F', '/'));
}
next();
});
I just stumbled over your question while facing a similiar problem.
Think this is because an id shall identify one single resource and not a nested structure/path to a resource.
Though I haven't solve my problem yet, what you probably want to use is a customQueryString:
https://router.vuejs.org/api/#parsequery-stringifyquery
https://discourse.algolia.com/t/active-url-with-vue-router-for-facet-and-queries/3399
I fixed it by creating helpers for generating hrefs for :to attributes of vue router link.
First i made router accessible for my new helper service like here Access router instance from my service
Then i created router-helpers.js and here i made my helpers, here is an example
import Vue from 'vue'
import router from '../router.js'
// replace %2F in link by /
const hrefFixes = function(to) {
return to.replace(/%2F/g, '/')
}
// my link helper
Vue.prototype.$linkExample = attr => {
// create "to" object for router resolve
const to = { name: `route-name`, params: { param1: attr } }
// this will resolve "to" object, return href param as string
// and then i can replace %2F in that string
return hrefFixes(router.resolve(to).href)
}
Just include this service once in your Vue application an then just use this helper like this
<router-link :to="$linkExample(attr)">text</router-link>
I'm new to Vue now working with its router.
I want to navigate to another page and I use the following code:
this.$router.push({path: '/newLocation', params: { foo: "bar"}});
Then I expect it to be on the new Component
this.$route.params
This doesn't work.
I also tried:
this.$router.push({path: '/newLocation'});
this.$router.push({params: { foo: "bar"}});
I've inspected the source code a bit and noticed this property gets overwritten with a new object {}.
I'm wondering is the params use is other than I think?
If not, how to use it?
Since you want to pass params to the component of the respective route you route object's path property should have a dynamic segment denoted by : followed by the name of the key in your params object
so your routes should be
routes: [
{path: '/newLocation/:foo', name: 'newLocation', component: newComponent}
]
Then for programmatically navigating to the component you should do:
this.$router.push({name: 'newLocation', params: { foo: "bar"}});
See that I am using name of the route instead of path as you are passing params by the property params.
if you want to use path then it should be:
this.$router.push({path: '/newLocation/bar'});
by the path approach the params will automatically map to corresponding fields on $route.params.
Now if you console.log(this.$route.params) in your new component you will get the object : {"foo": "bar"}
Try using query instead of params
this.$router.push({path: '/newpath', query : { foo: "bar"}});
And in your component
console.log(this.$route.query.foo)
The easiest way I've found is to use named routes along with the params options. Let's say you have a router file that looks like this:
And you want to reach the "movie" page with some ID. You can use Vue's router link component (or Nuxt's link component) to reach it like this:
Vue:
<router-link :to="{ name: 'movie', params: { id: item.id } }">{{ item.title }}</router-link>
Nuxt:
<nuxt-link :to="{ name: 'movie-id', params: { id: item.id } }">{{ item.title }}</nuxt-link>
Note that the name parameter must match the "name" attribute of the desired route in the router file. And likewise, the parameter name must match.
Nuxt creates the route file for you automatically when you create a
new page. To see what name Nuxt gives its routes, go to the .Nuxt
folder in your project and look for a "router.js" file
Isn't it generally considered an anti pattern to bind the properties to the router?
It's a much more DRY solution to have them bind to the component it's self, which I actually believe the Vue router does. Please see: https://router.vuejs.org/en/essentials/passing-props.html for more info on the best practices here
Can you try accepting the property in the props: [] property of your component? You can see how to do that here: https://v2.vuejs.org/v2/guide/components.html#Props
Please do pop up if you have any questions! Happy to help further.