Browser back button not working properly on router query param change - vue.js

I have a simple route definition:
{
path: 'customers',
name: 'customers',
component: Customers,
props: true
}
To start with, I am on the general /customers route.
But I can use query params on this route, and react on changes to load the corresponding data:
this.$router.push({ name: 'customers', query: { customerId: '123' } });
#Watch('$route.query.customerId')
customerIdChanged() {
this.loadCustomer($route.query.customerId);
}
This works as intended, but let´s say i push three different customerId´s to this router, and now want to go back in browser history and load the previous customers one by one. I can´t because a query change is not considered a "real" url change. So when I push back, I get routed back to the initial /customers route.
How to make these query changes count as real url changes so I can use the back button?
I could maintain my own browser history stack, but I would rather not, and think there is a more "official" solution?
Thanks!
---- UPDATE ----
I actually had an error in my code. Before i pushed to the route, i replaced the route with /customer. And then pushed the customer query route. This was why the back navigation did not work.

What about dynamic matching? You could use:
{
path: 'customers/:id',
name: 'customers',
component: Customers,
props: true
}
this.$router.push({ name: 'customers', params: { id: '123' } });

Related

Router link is throwing error when navigating away from route which contains a param vue js 3

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>

Vue redirect back to '/' if 404 not found

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' },
}

Nuxt pass props programmatically, through router

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.

Vue router not matching route with more than one slash

basically my issue is that I want to pass a router prop called name into an article route, so something like /article/:name. When I direct to that route internally, like with $router.push(name: 'article', params: {name: 'something'}), it works just fine. But when I then use that url, /article/something, the route doesn't match and the page is blank.
But if I just use /:name instead of /article/:name, everything works just fine. Does anyone have any idea why the /article part could be causing the route to fail to match? Thanks in advance.
EDIT: Route definition:
{
path: '/article/:name',
name: 'article',
component: () => import('../views/Article.vue'),
props: true,
}
When I navigate to /article/something, the page is blank, no matter what something is. But if I have the following route definition:
{
path: '/:name',
name: 'article',
component: () => import('../views/Article.vue'),
props: true,
}
and navigate to /something, it works just fine.

How to make stepped navigation using vue router?

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.