vue-router query parameter as array with keys - vue.js

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 .

Related

Can not replace query string via Vue router

I have a Vue app which needs to remove query parameter from url. Url looks like http://localhost:8080/campaigns/279707824dd21366?screenshot=1 Needs to remove screenshot param without redirect. So I found solution which looks like this:
if( this.$route.query.screenshot ) {
this.screenshot();
const query = this.$route.query;
delete query.screenshot;
this.$router.replace({query: null}).catch((error)=>{
console.log(error);
});
}
This throws me an error without redirect:
NavigationDuplicated: Avoided redundant navigation to current
location: "/campaigns/279707824dd21366?screenshot=1".
I also tried this:
if( this.$route.query.screenshot ) {
this.screenshot();
const query = this.$route.query;
query.screenshot = null;
this.$router.replace({query});
}
What is wrong with this code? Thanks for any help.

Getting requested page route in Nuxt middleware

I have a very simple 'named' Nuxt middleware set up (taken from the docs) which checks in the store to see whether a user is authenticated before they can navigate to certain routes. If the user is not authenticated, they are directed to a straightforward form in which they have to provide an email address to gain access (at http://example.com/access). All of that works fine, after they fulfil the middleware's store.state.authenticated check they can navigate around no problem.
export default function ({ store, redirect }) {
if (!store.state.authenticated) {
return redirect('/access')
}
}
My question is, once the user has entered their email address, I have no way of knowing what route they were initially trying to access. I've looked at other questions here about passing data between routes but because of the way the middleware works these solutions don't seem to be feasible.
I really would rather not set the slug in the vuex state as this will lead to a whole other set of complications – I also don't mind setting the intended slug as a query or a param on the /access url. I have read through the docs for the Nuxt redirect function and realise you can pass a route.query as an argument. So it seems that you could potentially do something like this:
return redirect('/access', intendedSlug)
...or, if using params(?):
return redirect(`/access/${intendedSlug}`)
But I don't know how to pass that intendedSlug value to the middleware in the first place as it's not exposed on the context passed to the function or anywhere else. It seems like this would be a common problem, but I can't find any simple solutions – any help would be really appreciated!
To help #Bodger I'm posting how I resolved this, it may not be perfect and it's working on a slightly older version of Nuxt (I know 😵!) but this is how I resolved the issue.
.../middleware/authenticated.js
export default function (context) {
const path =
context.route.path.length && context.route.path[0] === '/'
? context.route.path.slice(1)
: context.route.path
const pathArray = path.split('/')
if (process.server && !context.store.state.authenticated) {
return context.redirect('/access', pathArray)
} else if (!context.store.state.authenticated) {
return context.redirect('/access', pathArray)
}
}
The pathArray is then accessible in my /access page.
.../pages/access.js
data() {
return {
attemptedRoutePathArray: Object.values(this.$route.query)
...
}
},
...
computed: {
attemptedRouteURL() {
return new URL(
this.attemptedRoutePathArray.join('/'),
process.env.baseUrl
)
},
...
}

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}})

I18n translations not rendering in Datatable initializations?

I am trying to apply translations to a jquery dataTable. ie.
myTable.DataTable({
language: {
paginate: {
next: (I18n.t('filters.paginate.next')),
previous: (I18n.t('filters.paginate.previous'))
}
}
});
When I run:
I18n.locale //=>en (even when the locale is changed)
Below, you see the I18n json shows two different locales for the same value, only is picking up one in brackets, even though they are the same attribute ?
After some time I have found the reason for the issue was that the function I was using to initialize my dataTables was IIFE (function() { })();, and was being processed before $(document).ready, and the correct I18n locale would not update for my translations in time. So I used a regex on the URL query string with a function called in the IIFE, and set the I18n.locale to the found value:
function QueryString(item){
var svalue = location.search.match(new RegExp("[\?\&]" + item + "=([^\&]*)
(\&?)","i"));
return svalue ? svalue[1] : svalue;
}
(function() {
I18n.locale = QueryString('locale');
//initialized tables and added translations
.... })();

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.