Vue 3 router with long url-param including special chars not working as intended? - vue.js

I have a router in Vue looking like this:
{
path: '/temporaryList/:tempUrl',
name: 'temporaryList',
component: () => import('../views/TemporaryListView.vue')
}
I want to send a value for the "tempUrl"-param that could for example look like this:
https%3A%2F%2Fwww.amazon.se%2F%5Bn%5Btest%5B~%5B
(this value is coming from encodeURIComponent() function, so it should be able to be used in the URL)
This does not seem to work for some reason, When I try to access this page I get:
"There was no web page at the URL: http://localhost:3000/temporaryList/https%3A%2F%2Fwww.amazon.se%2F%5Bn%5Btest%5B~%5B "
I have built this exact same solution with node and express where this didn't seem to be an issue. I don't know if the value of the param I send is to long for Vue? It also seems like Vue does not like when a params includes a "%" for example.
Is there any way you can make Vue routers allow this type of param-value?

Vite uses the decodeURIComponent function on the request URL. The value of the param i sent had "%" included in it which made Vite read every "%" as a "/". That made Vite searchfor a location that did not exist.
This npm-package solved my issue: https://github.com/ivesia/vite-plugin-rewrite-all

Related

vue router.push in nuxt using route.name

I use nuxt and have following Problem. My old code looks like this:
this.$router.push({path: "about/me"})
Now I need to make the same call with some params:
this.$router.push({path: "about/me", params: {sendNotification: "1"}})
This obviously doesn't work since vue-router only allowes to use params with name and not path, so it has to look like:
this.$router.push({name: ..., params: {sendNotification: "1"}})
I could do it with query instead of params but I don't want my url to look ugly.
The problem with nuxt is, or at least this is my understanding of nuxt, that it generates the route names using folder structure and in my case also the locale. So the name of this route is actually: "personal-about-me__en".
So my question: Is there a way to get the route.name dynamically, so I could write something like:
this.$router.push({name: getRouteNameByPath("about/me"), params: {sendNotification: "true"}})
The name of the route path is matching the name prop that you can give to the .vue file. So, write is as name: 'AboutMe' key property and use it in the router with { name: 'about-me' }.
Also, vue devtools have a router tab with the name of all the available routes.
This obviously doesn't work since vue-router only allowes to use params with name and not path.
Why do you need to pass params alongside the path? You are supposed to add the params to the path itself, which is why vue-router doesn't allow a separate params object.
So for e.g. assuming your dynamic route is about/me/:sendNotification, you can either provide params with the named route:
this.$router.push({name: ..., params: {sendNotification: "1"}});
which directs you to about/me/1.
OR you can push the entire path including the params
this.$router.push({ path: 'about/me/1' });
Both will produce the exact same result.

Nuxt encode/decode URI with double colon

My URLs have double colon on them.
I push a path to Nuxt router which has : as a part of it.
export default {
router: {
extendRoutes (routes, resolve) {
routes.push({
name: 'custom',
path: 'towns' + '(:[0-9].*)?/',
component: resolve(__dirname, 'pages/404.vue')
})
}
}
}
When I point to http://localhost:3000/towns:3 , for example, the : is translated as %3Aon the URL leading to this error message:
Expected "1" to match ":[0-9].*", but received "%3A2"
How to revert this to : ?
I tried encodeURI(), decodeURI(), encodeURIComponent() and decodeURIComponent() in vain.
A demo for the ones who wants to try: nuxt-extend-routes
Any suggestions are welcome
Vuex is using vue-router and vue-router is using path-to-regexp to parse router path configuration
It seems to me, that you are trying to use Unnamed Parameters which doesn't make sense because vue-router/vuex need the name of the parameter to pass it down to Vue component behind the route
Why don't just use named parameters ?
{
path: '/towns:id(:\\d+)',
name: 'Page 3',
component: Page3
}
Sure, result will be that $route.params.id value will be prefixed with : and all router-link params must be :XX instead of 'XX' but that's something you can deal with. vue-router (path-to-regexp) is using : to "mark" named path parameters ...there's no way around it
You can take a look at this sandbox. Its not Nuxt but I'm pretty sure it will work in Nuxt same way....
Update
Well it really doesn't work in Nuxt. It seems Nuxt is for some reason applying encodeURIComponent() on matched path segments and throws an error. It works when server-side rendering tho (it throws some error on client still)...
Firstly, I concur with Michal Levý's answer that there's a library bug here. The line throwing the error is here in the Nuxt source:
https://github.com/nuxt/nuxt.js/blob/112d836e6ebbf1bd0fbde3d7c006d4d88577aadf/packages/vue-app/template/utils.js#L523
You'll notice that a few lines up the segment is encoded, leading to : switching to %3A.
However, this line appears to have originated from path-to-regexp:
https://github.com/pillarjs/path-to-regexp/blob/v1.7.0/index.js#L212
It isn't trivial to fix this bug because the encoding is not simply 'wrong'. There's a lot of stuff going on here and by the time that line is reached the parameter values have been URL decoded from their original values. In the case of our unencoded : that causes problems but in other cases, such as matching %3A, the encoding would be required.
The handling of encoding within path-to-regexp is a delicate topic and we aren't helped by the old version being used. This also makes it more difficult to come up with a suitable workaround in your application.
So, let's see what we can do...
To start with, let's consider the path:
path: 'towns' + '(:[0-9].*)?/',
Bit odd to concatenate the strings like that, so I'm going to combine them:
path: 'towns(:[0-9].*)?/',
The / on the end isn't hurting but it seems to be unnecessary noise for the purposes of this question so I'm going to drop it.
On the flip side, not having a / at the start can cause major problems so I'm going to add one in.
The .* is suspicious too. Do you really mean match anything? e.g. The current route will match towns:3abcd. Is that really what you want? My suspicion is that you want to match just digits. e.g. towns:3214. For that I've used [0-9]+.
That leaves us with this:
path: '/towns(:[0-9]+)?',
Now, the : problem.
In general, route paths are used in both directions: to match/parse the URL and to build the URL. Your use of an unnamed parameter makes me wonder whether you only intend to use this route for matching purposes.
One option might be this:
path: '/towns:([0-9]+)',
By moving the : outside the parameter it dodges the encoding problem.
There are two problems with the code above:
The colon/number suffix is no longer optional on the URL. i.e. It won't match the path /towns as the original route did. This can be solved by registering /towns as a separate route. I'm not aware of any other way to solve this problem with the available version of path-to-regexp.
You won't be able to use it to build URLs, e.g. with nuxt-link.
If you need to be able to use it to build URLs too then you could use a named parameter instead:
path: '/towns::town([0-9]+)',
The :: part here is potentially confusing. The first : is treated literally whereas the second : is used as a prefix for the town parameter. You might then use that with nuxt-link like this:
<NuxtLink :to="{ name: 'custom', params: { town: 4 } }">
...
</NuxtLink>

Losing router.params on page refresh

I'm encountering an issue with vue-router.
I got a list of posts in the homepage. When I click on one of them, it redirects to the post page such as :
<router-link :to="{ name: 'article', params: {id: article.id, slug: article.slug } }"></router-link>
Everything is working perfectly, I can retrieve the data of the correct article using this.$route.params.id in a getter.
My issue : When I reload on an article page, this.$route.params.id is undefined, which causes the entire application to crash.
How can I save the router.params despite a page reload ?
What backend are you using? You need to enable history mode on your router, as well as make some additional configuration changes on your backend web server. Please refer to this link for the additional server side configuration changes you will need to make for this to work properly.
Also, please make note of this 404 caveat when using history mode..
Edit: you could try something like this since the ID remains persistent in the URL: Look for the solution from MIKE AXLE
I don't know if anyone else if facing the same issue, but I was having a problem getting route params on refresh. The route parameter I was trying to get was an ID number and I use that ID to fetch data and populate the page. I found (through many console logs) when I refreshed, the number was turning into a string and thats why the page was not working. I sorted it out but casting the ID to number before using it:
Number($route.params.id)
You can also use query instead of params
<router-link :to="{ name: 'article', query: {id: article.id, slug: article.slug } }"></router-link>
and to get value on redirecting page
this.$route.query
I'm not sure what is your route definition, the problem can be that only one of the params presented in the route URL (e.g. /article/:slug).
When you invoke a route (by clicking on router-link or calling router.push), you passing both params directly and they persist in the memory. That's why both are accessible.
But when you reload the page - everything that Vue can do is to parse your URL.
Means only one param parsed because only one param is present.
As a solution you can:
use both params in the route URL (e.g. /article/:id/:slug);
or use one param and call your API to retrieve remaining information (e.g. get id by slug if your route is /article/:slug).
I had the same issue pass the url in router
/article/:id/:slug
you will not loose your params after resfresh because whenrefreshng vue will take only data from url and forget if you passed params
You should route like this:
{
path: '/article/:id/:slug',
name: 'article',
}
In your view when routing do it like this:
this.$router.push({ name: 'article', params: { id: articleID, slug: articleSlug}});
You're welcome! 😉

Use route parameters with `app.use` on Express

I cannot use route parameters with app.use on Express 4.16.2.
I have a statement like this:
app.use('/course-sessions/:courseSessionId/chapter-sessions', chapterSessionsRouter)
And, in chapter sessions router:
// Index.
router.get('/', ...resource.indexMethods)
When I got '/course-sessions/0/chapter-sessions/', I have 404.
Then I am trying a statement like this:
app.get('/course-sessions/:courseSessionId/chapter-sessions', ...chapterSessionResource.indexMethods)
Now I have the result I want. So route parameters don't work with app.use.
While I am researching, I got this GitHub issue and this pull request which closes the issue. But it seems that the issue is still around here. Or do I make something wrong?
You have to setup your router in a different way, try using mergeParams to access parameters in parent routes.
let router = express.Router({ mergeParams: true });
See docs: http://expressjs.com/en/api.html
I’d do only app.use('/course-sessions/', chapterSessionsRouter) and handle the id inside the router.

Passing variables into JavaScript in ExpressJS/PassportJS/Jade app

This is essentially a continuation of the question here: Nodejs Passport display username.
app.get('/hello', function(req, res) {
res.render('index.jade', { name: req.user.username });
});
So users log in via PassportJS, and goes to index.jade, which contains #{name} in the body, which will be replaced by the value of req.user.username.
Question: Is it possible to use the value of req.user.username in index.jade's JavaScript? I tried assigning its value to a variable but it doesn't work.
I have been using the trick of having a hidden input with #{name} as value:
input(type='hidden', id='variableName', value='#{name}')
Then JavaScript can access this value using:
$("#variableName").val()
This works. But does it have any potential downside like security issues? What is the right way to do this?
You have a few options. One of them is what you did and put the value inside you html. You can also solve it by doing:
script
window.name = #{name};
This will create an inline script that sets the variable. The other option you have is using ajax. That means you probably need to make an extra route to reply to that request.