I want to make stepped navigation for user signup page
and i wanna make each step a different route but i need to keep url the same for each of it, so that user won't be able to go straight to step 3.
here is what i currently have
routes:
{
path: '/signup',
component: SignupPage,
children: [
{ path: '', name: 'signup.step1', component: SignupStep1 },
{ path: '', name: 'signup.step2', component: SignupStep2 },
{ path: '', name: 'signup.step3', component: SignupStep3 },
{ path: '', name: 'signup.step4', component: SignupStep4 }
]
}
SignupPage:
<header>...</header>
<router-view />
<footer>...</footer>
SignupStep1:
methods: {
nextStep () {
this.$router.push({ name: 'signup.step2' })
}
...
}
but when nextStep method called nothing seems to change
I'll answer this question short.
Two optimal ways to solve this task - use Vuetify and its ready-to-use Steppers-component and the second one - pass data through params from one step to the next one.
Let me explain the second option: vue-router allows us to easily pass any type of data from one url to another without even showing that data somehow to the end user. How to pass data between urls you can read in vue-router docs and in your case you don't even need 4-5-6 components, it will be enough to use 1 component + tab bars or any other element for switching steps.
but when nextStep method called nothing seems to change
That happens because you have 4 paths with the same value - an empty value. vue-router searches routes from top to bottom and if it finds one that matches current path no other records would be checked, thats why you see only singup-page.
Related
In Nuxt, I have an admin dashboard with a special layout (sidebar), where I use <NuxtChild> to render child routes:
Admin.vue
<NuxtChild :key="$route.path" />
Routes (simplified):
{
path: "/admin",
name: "admin",
component: Admin,
children: [
{
path: '/admin/event/create',
name: 'EventCreate',
component: EventCreate,
props: true
}
// many more routes...
]
}
Now, I want the EventCreate route to also be available alone, in a regular isolated context (NOT in the admin dashboard). This is simple enough with another route. This works fine:
{
path: '/event/create',
name: 'EventCreate',
component: EventCreate,
props: true
}
PROBLEM:
My routes config file will be too messy, with duplicated routes that essentially only differ by path.
Note: I do not use Nuxt's standard file-based routing. Instead all of my route's are defined in one central config file (for many reasons, and my preference). This is done using the Nuxt-Community router library: https://github.com/nuxt-community/router-module. The end result is essentially how Vue-Router works (ie routes defined in a config file).
QUESTION:
Is there a way to define a route once, and have it apply to different contexts (alone or as a child inside another route)?
On a higher level perhaps there's a better way to handle this context switching (plain page vs child-inside-dashboard). In any case, <NuxtChild> works well aside from this, and I wanted to keep using it.
Any suggestions; different idea?
it's easy you can use alias option of vue-router:
{
path: "/admin",
name: "admin",
component: Admin,
children: [
{
path: 'event/create', // not repeat path from root
alias: ['/event/create'],
name: 'EventCreate',
component: EventCreate,
props: true
}
// many more routes...
]
}
and one more note never use a path that starts with / and repeat the parent path in children it doesn't work at all it's verbose, confusing and potentially error-prone
Share route properties with an object
Based on comment by #Estus Flask, here's one way to have a cleaner routes definition:
Use a object to store shared properites, and use it in relevant routes, reducing duplication. Still, you must still have separate routes for contexts, which makes sense.
Object to hold shared properties:
const MyEventCreateRoute = {
component: EventCreate,
props: true,
// other stuff
}
Routes use the shared properties with spread operator:
// Basic route; not in dashboard:
{
path: '/event/create',
name: 'EventCreate',
...MyEventCreateRoute
}
// Route in admin dashboard; renders inside <NuxtChild>:
{
path: "/admin",
name: "admin",
component: Admin,
children: [
{
path: '/admin/event/create',
name: 'AdminEventCreate',
...MyEventCreateRoute
}
]
}
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 have a Vue application with the following routes:
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'input',
component: Input
},
{
path: '/result/:city',
name: 'result',
component: Result
}
]
})
I know that if I do a new path with path: '*' and component: someErrorPage, I can show an error page. However, I'd like to redirect back to the input path so they can try again.
EDIT:
After doing some research and looking at my app, I found that if I search an invalid query, it will take me to corresponding route anyway, but not show me the data. Example: If I search a valid city (eg. New York), I am redirected to localhost:8080/result/New York with the correct data. However, if I do an in valid query (eg. a;fldkalf), I will be taken to localhost:8080/result/a;fldkalf without any data. This means that path: '*' will not help me here.
EDIT 2:
I think I may have found something that will help, but I am not sure how to execute it. Vue has something called navigation guards (https://router.vuejs.org/guide/advanced/navigation-guards.html#global-before-guards). If someone could help me make sense of it, that'd be great.
You can add redirect for * (not found) route:
{
path: '*', // make sure this is the last route in Array
redirect: { name: 'input' },
}
I'm trying to implement routing over an spa which was only swapping out components based on setting true/false properties on the main VUE instance. I'm using the official Vue router for VUE.JS 2
There is a component, which i routed to the following path:
{
path: '/Foe/Bar/Details/:id',
components: {
layerTop: 'barDetail',
layerMiddle: notImportant
},
props: { layerTop: true }
},
So when the user clicks on the details button my components load as expected. My problem is when I try to navigate from this route to a new one but I want to keep my named 'layerTop' router-view as currently is. Basically I dont want to change the 'layerTop' view, just the layerMiddle view.
So I was thinking my path would look something like this:
path: 'Foe/Bar/Details/:barId/Categories/:categoryId
But I don't know how to map the :barId param to the Bar component's prop, and the categoryId to the Category comp's prop.
When it is a single parameter it works just like in the example above.
I'm pretty new to Vue and the router especially, tried to find an example on the docs but couldnt. Thank you for any input.
Check out the nested routes documentation.
https://router.vuejs.org/en/essentials/nested-routes.html
routes: [
{path: "/foo/bar". component: FooBar,
children [
path: "/:id", component: FooBarDetails,
children: [
{path: "categories/:categoryid", component: Category}
]
]
}
]