NuxtJS change query params and reload page - vue.js

I have a route in my NuxtJS application that accept query parameters. I'm trying to implement a logic that allow the user to change the query parameters and reload the page.
I tried:
// this does not work because I'm already in "mypage" and "push" does not reload the same page
this.$router.push(`/mypage?param1=${value1}&param2=${value2}`)
// same result as above
this.$router.push({ path: '/mypage', query: {param1: value1, param2: value2}})
// this is able to change the query parameters but on reload they are reverted to the originals
this.$router.replace({ query: {param1: value1, param2: value2} })
window.location.reload()
// This reload the page but the query parameters are reverted as well
this.$router.go(`/mypage?param1=${value1}&param2=${value2}`)
Any suggestions?

You should use the 2nd method to update query params.
this.$router.push({ path: '/mypage', query: {param1: value1, param2: value2}})
It's really a bad practice to force reload a page, instead, you should set up a watcher or a computed for your query.
E.g.
watch: {
'$route.query'() {
// do something
}
},
If this doesn't work for your please provide more information about your problem.

This is only a workaround:
thanks to this: https://github.com/vuejs/vue-router/issues/1182#issuecomment-405326772
I was able to work around the issue by using javascript:
window.history.pushState({},'',`/mypage?param1=${value1}&param2=${value2}`)
window.location.reload()
of course this is not an optimal solution but it gets the work done until someone come out with a more proper solution here. thanks.

You can do it use promise.then() and $nuxt.refresh()
// before
this.$router.replace({ query: {param1: value1, param2: value2} })
window.location.reload()
// after
this.$router.replace({ query: {param1: value1, param2: value2} }).then(() => {
this.$nuxt.refresh();
});

if u want only to change query param without reloading the page, use Fabio Magarelli solution:
window.history.pushState({},'',`/mypage?param1=${value1}&param2=${value2}`)
for change with reload - use this:
this.$router.push({path: this.$route.path, query: { param1: 'param1', param2: 'param2' }})

Use watchQuery
export default {
watchQuery: ['page']
}
Doc: https://nuxtjs.org/docs/components-glossary/watchquery/#the-watchquery-property

Related

useInfiniteScroll utility of Vueuse is fetching same items again

Here is a reproducable stackblitz -
https://stackblitz.com/edit/nuxt-starter-jlzzah?file=components/users.vue
What's wrong? -
My code fetches 15 items, and with the bottom scroll event it should fetch another 15 different items but it just fetches same items again.
I've followed this bottom video for this implementation, it's okay in the video but not okay in my stackblitz code:
https://www.youtube.com/watch?v=WRnoQdIU-uE&t=3s&ab_channel=JohnKomarnicki
The only difference with this video is that he's using axios while i use useFetch of nuxt 3.
It's not really a cache issue. useFetch is "freezing" the API URL, the changes you make to the string directly will not be reliably reflected. If you want to add parameters to your API URL, use the query option of useFetch. This option is reactive, so you can use refs and the query will update with the refs. Alternatively, you can use the provided refresh() method
const limit = ref(10)
const skip = ref(20)
const { data: users, refresh: refreshUsers } = await useFetch(
'https://dummyjson.com/users',
{
query:{
limit,
skip
}
}
);
//use the data object directly to access the result
console.log(users.value)
//if you want to update users with different params later, simply change the ref and the query will update
limit.value = 23
//use refresh to manually refresh the query
refreshUsers()
This results in a first API call http://127.0.0.1:8000/api/tasks?limit=10&skip=20 and then a second with the updated values http://127.0.0.1:8000/api/tasks?limit=23&skip=20
You can leave the cache alone, as it is just a workaround, and will not work reliably.
[Updated] The useFetch() documentation is now updated as described below.
The query option is not well documented yet, as discussed in this nuxt issue. I've created a pull request on nuxt/framework to have it reflected in the documentation. Please see a full explanation below:
Using the query option, you can add search parameters to your query. This option is extended from unjs/ohmyfetch and is using ufo to create the URL. Objects are automatically stringified.
const param1 = ref('value1')
const { data, pending, error, refresh } = await useFetch('https://api.nuxtjs.dev/mountains',{
query: { param1, param2: 'value2' }
})
This results in https://api.nuxtjs.dev/mountains?param1=value1&param2=value2
Nuxt3's useFetch uses caching by default. Use initialCache: false option to disable it:
const getUsers = async (limit, skip) => {
const { data: users } = await useFetch(
`https://dummyjson.com/users?limit=${limit}&skip=${skip}`,
{
initialCache: false,
}
);
//returning fetched value
return users.value.users;
};
But you probably should use plain $fetch instead of useFetch in this scenario to avoid caching:
const getUsers = async (limit, skip) => {
const { users } = await $fetch(
`https://dummyjson.com/users?limit=${limit}&skip=${skip}`
);
//returning fetched value
return users;
};

Vue router: Dynamically set query key inside router.push()

I am new to Vue and I have created a project where I perform GET-requests based on current URL.
I have a function where I want to be able to set the dynamic value of filterType to the query key inside the router.push().
The function I have now just pushes filterType as a string. Ive been researching and havent found any answers regarding this issue. Grateful for any input or wisdom.
setFilter(filterType, filterValue){
if(filterValue){
this.$router.push({ query: Object.assign({}, this.$route.query, { filterType: filterValue })}).catch(err =>{});
}
else {
let query = Object.assign({}, this.$route.query);
delete query.filterType;
this.$router.replace({ query }).catch(err =>{});
}
},
Assign it as a key to the query object:
if(filterValue){
const query = this.$route.query
query[filterType] = filterValue
this.$router.push({path:'/', query:query})
}
Try this code
let newQuery = {filterType: filterValue};
this.$router.push({name: 'route-name', query: {...this.$route.query, ...newQuery}})

vue-router query parameter as array with keys

I need to generate a vue-router link that contains an array with string keys as a query parameter.
I want the resulting URL to look like
url?param[key]=value
I need these kinds of query parameters to match an existing backend infrastructure, so renaming/refactoring them is not an option.
I've tried to use a router-link like the one below, but the param object just get's serialized as %5Bobject%20Object%5D. Maybe there is an option to change the way this object is serialized within vue-router?
<router-link :to="{name: 'xyz', query: {param: 'value'}}">link</router-link>
Does anyone have helpful input? Thank you :)
After spending some time vue-router GitHub issues and their docs, I figured it out.
When creating your RouteConfig, import qs and set the parseQuery and stringifyQuery methods as follows:
parseQuery: (query: any): object => {
return qs.parse(query);
},
stringifyQuery(query: any): string {
let result = qs.stringify(query, {encode: false});
return result ? ('?' + result) : '';
}
It is important to include {encode: false}, otherwise the square brackets will get URL encoded.
Addition to Martin's comment,
Exact Router config should be :
// https://github.com/ljharb/qs
import qs from 'qs';
const router = new Router({
routes: [
// ...
],
// set custom query resolver
parseQuery(query) {
return qs.parse(query);
},
stringifyQuery(query) {
var result = qs.stringify(query);
return result ? ('?' + result) : '';
}
});
and query parameters inside routes will be automatically converted url string and parsed as an object when accessing $router.query .

vuejs this.$route issue with address bar

When I remove a parameter, It does not take effect in address bar.
I tried following line to remove parameter from URL.
delete this.$route.query[parameter_name];
See below url, Notice following things.
In console query object is empty but address bar having all parameters.
I tried following lines to remove applicants and branches parameters from URL. It only effected in console as you can see query object is empty but URL is still there.
delete this.$route.query['applicants'];
delete this.$route.query['branches'];
But still address bar is having all removed params.
donate#/?applicants=Female&branches=2207962
Using delete will delete the property but will not update the address bar.
You need to specify a redirect programmatically. See Programmatic Navigation.
You can use
this.$router.push('donate')
Or
this.$router.replace('donate')
to replace the current history entry (see comment from #thanksd)
This will work with $router.push or $router.replace to clear the query string.
Clear the query string inside a component lifecycle hook.
mounted() {
this.$router.replace({ query: { '': null } });
}
Clear the query string on redirect.
$router.push({ path: 'url-path', query: { '': null } })
$router.replace({ path: 'url-path', query: { '': null } })
Remove old query string values and replace with new values.
$router.push({path: 'url-path', query: {'': null, lastname: 'Ever', firstname: 'Greatest'}})
$router.replace({ path: 'url-path', query: { '': null token: 'coolToken' })

Dynamically Adding / Removing Route in Durandal Router when application is loaded

I need help in dynamically adding/removing route in Durandal Router. What I want is after user is logged in then I would be able to add or remove specific route depending upon logged in user's type.
I tried to add/remove route from visibleRoutes/allRoutes array ... but get binding exception from knockout library...
I was hoping it would be common scenario... but still couldn't find any solution ... please help me in fixing this issue.
Thanks.
Wasim
POST COMMENTS:
I tried this function to dynamically hide/show route... and similary tried to add/remove route from allRoutes[] ... but then get exception on knockout bidning
showHideRoute: function (url,show) {
var routeFounded = false;
var theRoute = null;
$(allRoutes()).each(function (route) {
if (url === this.url) {
routeFounded = true;
var rt = this;
theRoute = rt;
return false;
}
});
if (routeFounded)
{
if (show)
{
visibleRoutes.push(theRoute);
}
else
{
visibleRoutes.remove(theRoute);
}
}
}
In Durandal 2.0.
You can enumerate the routes to find the one you wish to show/hide.
Then change the value of: nav property
Then run buildNavigationModel();
here is an example:
// see if we need to show/hide 'flickr' in the routes
for (var index in router.routes) {
var route = router.routes[index];
if (route.route == 'flickr') {
if (vm.UserDetail().ShowFlickr) { // got from ajax call
// show the route
route.nav = true; // or 1 or 2 or 3 or 4; to have it at a specific order
} else if (route.nav != false) {
route.nav = false;
}
router.buildNavigationModel();
break;
}
}
Durandal 2.0 no longer has the method visibleRoutes. I found that the following works for me.
router.reset();
router.map([
{ route: 'home', moduleId: 'home/index', title: 'Welcome', nav: true },
{ route: 'flickr', moduleId: 'flickr/index', title: '', nav: true }
])
.buildNavigationModel()
.mapUnknownRoutes('home/index', 'not-found');
This removes all previous routes, if you want to maintain current routes you could try using the router.routes property to rebuild the array of routes.
I had a similar requirement. If I were you, I would take another approach. Rather than adding/removing routes when application loads - get the right routes to begin with per user type.
Two options, (I use both)
1) have a json service provide the proper routes per user type, this approach would be good if you need to 'protect/obscure' routes... i.e. I don't want the route referenced on any client resource.
2) A simpler solution see Durandal.js: change navigation options per area
You can have a settings property identify the user type.
I hope this helps.
I had a similar problem: First, router.visibleRoutes() is an observable array. In other words, when you change its value, the routes automatically update. However, the items in this array are not observable, so to make a change you need to replace the entire array and not just make a change to a single item in it.
So, all you have to do is find which item in this array you want to remove, and then create a new array without this item, and set router.visibleRoutes() to this new array.
If, for example, you find out the it is the 3rd item, then one way of doing it is:
router.visibleRoutes(router.visibleRoutes().splice(2, 1))
Note that splice() returns a new array where an item is removed. This new array is put into router.visibleRoutes.