How to handle multiple queryParams in Angular2
Asked Answered
S

3

7

I'm trying to implement a filtering mechanism in a new Angular2 app, that would allow me to filter a list of entries in an array. The entries may have around 20 properties that could be filtered on. I have so far created a list of filters in one component and then a list component that is routed to, as a child. I then planned to pass the filters as queryParams through the router. Starting with just one filter this was fine:

On the send side I had:

this.router.navigate(['/findlist'], {queryParams: {'g': myParam}});

The on the receive side, I had:

this.subscription = this.route.queryParams.subscribe(
  (queryParam: any) => this.myFilter = queryParam['g']
);

I then pass myFilter to a filter pipe to do the match and filter. All OK so far.

However, I can't figure out how to scale this up to allow for multiple potential Params, most of which would be blank/not needed.

I can imagine that I would need to define an array holding ALL of the active filters through the queryParam, but the only documentation I can find, only ever shows examples with just one parameter passed. I've tried playing around with:

{queryParams: { pass an array here! }}

But my IDE registers an error if I put anything in other than a key:value pair.

I could probably just add in all the possible filters and their values each time, but that would create a URL string stupidly long each time, with most values blank or All etc., not very pretty.

So I think my workflow should be that on the send side I maintain an array of all the filters and their states and then each time one of the filter buttons is clicked, I first update the relevant value in the array and then pass the whole array through queryParams.

On the receive side somehow I have to receive and process the Param as an array and then extract each entry as variables to then process in the filter. I also want to be DRY, so don't really want several statements on the receive side effectively doing the same thing for different properties, simplistically it makes more sense to cycle through an array instead.

I hope that makes sense, I'd be grateful if anyone has a suggestion, even if it means passing the data in a different way. For example, I'm currently now looking to see whether I can just pass the data by creating a separate filter service and passing it using @Input instead.

Any ideas gratefully received (self taught amateur so probably missing something obvious !)

Thanks

Tony

Sweeten answered 21/12, 2016 at 14:9 Comment(2)
Possible simple solution, you could pass all your params as a single param, pipe delimited or something? key_val|key_val|key_val or some such. Then just grab that param value, split it on the pipe, then split each on the underscore. You could do this right up until whatever the limit is on the size of a router param (whatever that may be). (I'd think it wouldn't work, but you could even try it as a json string, that's a total longshot though I know).Unreserved
Do you need the URL to be distinct for different combinations of filters? If not, you can use a service hold the filters.Mweru
E
4

You could try it like this:

Define an array with your query params:

myQueryParams = [
    { id: 1, param: 'myParam' },
    { id: 2, param: 'myParam' },
    { id: 3, param: 'myParam' },
    { id: 4, param: 'myParam' },
    { id: 5, param: 'myParam' },
];

Put this array into one single query param:

this.router.navigate(['/findlist'], {
    queryParams: {
        filter: JSON.stringify(this.myQueryParams)
    }
});

Read the query param like this:

this.route.queryParams.subscribe((p: any) => {
    if (p.filter){
        console.log(JSON.parse(p.filter));
    }
});

You'll see something like this:

Screenshot of Chrome developer tools

Now you can parse this object. I think the URL looks a little bit ugly, but it should be functional. Try it out, I hope it helps you ;)

Eleanor answered 22/12, 2016 at 12:6 Comment(2)
Thank you for replying. I tried this quickly and yes it does work and yes the URL is indeed ugly!. I don't think I'd like to go ahead with the URLs as they are in this solution, so will wait to see if anyone else has another idea. I will also look into creating a filter service, if I can get that to work in the background instead. Thank you again!!Sweeten
@TonyJackson, you could do this this.router.navigate(['/findlist'], { queryParams: { param1: 'value1', 'param2': 'value2' } }); and then the url would look like localhost:4200/findlist?param1=value1&param2=value2Hypercatalectic
H
2

Try this.

this.router.navigate(['/findlist'], { queryParams: { param1: 'value1', 'param2': 'value2' } }); 

and then the url would look like

localhost:4200/findlist?param1=value1&param2=value2 

Finally, you could get back the route params by using the snippet below,

this.route.queryParams.subscribe((p: any) => {
    if (p.param1){
        console.log(JSON.parse(p.param1));
    }
 if (p.param2){
        console.log(JSON.parse(p.param2));
    }
});
Hypercatalectic answered 10/9, 2018 at 12:19 Comment(0)
A
1

I did like the below code. it worked for me.

onSubmit() {
    let query = {}
    query['age'] = '50'
    query['gender'] = 'male'      
    this.router.navigate(["/go"], { queryParams: query})
  }

URL would be localhost:4200/go?age=50&gender=male

Finally, You can subscribe your query params.

Arbalest answered 30/11, 2022 at 14:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.