How to handle multiple queryParams in Angular2

Tony Jackson picture Tony Jackson · Dec 21, 2016 · Viewed 9.3k times · Source

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

Answer

Philipp Kief picture Philipp Kief · Dec 22, 2016

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