282

I use angular2.0.0-beta.7. When a component is loaded on a path like /path?query=value1 it is redirected to /path. Why were the GET params removed? How can I preserve the parameters?

I have an error in the routers. If I have a main route like

@RouteConfig([
  {
      path: '/todos/...',
      name: 'TodoMain',
      component: TodoMainComponent
  }
])

and my child route like

@RouteConfig([
  { path: '/', component: TodoListComponent, name: 'TodoList', useAsDefault:true },
  { path: '/:id', component: TodoDetailComponent, name:'TodoDetail' }
])

then I can't get params in TodoListComponent. I am able to get

params("/my/path;param1=value1;param2=value2") 

but I want the classic

query params("/my/path?param1=value1&param2=value2")
FireGM
  • 2,971
  • 2
  • 12
  • 10
  • 1
    how you specified `@RouteConfig` for this `path`? – Pankaj Parkar Feb 28 '16 at 21:29
  • I found error. I have main route and child route and if i have main route like { path: '/todos/...', name: 'TodoMain', component: TodoMainComponent } and child route { path: '/', component: TodoListComponent, name: 'TodoList', useAsDefault:true }, it's not work and redirect to url without query params. – FireGM Feb 28 '16 at 22:15

17 Answers17

475

By injecting an instance of ActivatedRoute one can subscribe to a variety of observables, including a queryParams and a params observable:

import {Router, ActivatedRoute, Params} from '@angular/router';
import {OnInit, Component} from '@angular/core';

@Component({...})
export class MyComponent implements OnInit {

  constructor(private activatedRoute: ActivatedRoute) {}

  ngOnInit() {
    // Note: Below 'queryParams' can be replaced with 'params' depending on your requirements
    this.activatedRoute.queryParams.subscribe(params => {
        const userId = params['userId'];
        console.log(userId);
      });
  }

}

A NOTE REGARDING UNSUBSCRIBING

@Reto and @codef0rmer had quite rightly pointed out that, as per the official docs, an unsubscribe() inside the components onDestroy() method is unnecessary in this instance. This has been removed from my code sample. (see blue alert box in this tutorial)

Stephen Paul
  • 37,253
  • 15
  • 92
  • 74
  • 2
    I further suggest to replace the subscription with a promise - in this special case. this.activatedRoute.params.toPromise() .then(response => ...) .catch(error => ...); – dec Oct 17 '16 at 00:11
  • Where can I pass "activatedRoute"? – michali Nov 02 '16 at 12:26
  • 21
    From the official documentation: **Do I need to unsubscribe?** `The Router manages the observables it provides and localizes the subscriptions. The subscriptions are cleaned up when the component is destroyed, protecting against memory leaks, so we don't need to unsubscribe from the route params Observable.` – Reto Nov 22 '16 at 15:06
  • angular redirects without firing the subscription (or promise). I can see the original oAUth callback with the token,but then it redirects to the route without the query params and console.log(param) is just an empty object. – FlavorScape Dec 04 '16 at 02:15
  • Is there a difference between `switchMap()` and `subscribe()`? Because in the official documentation it's using `switchMap()`. – Sobhan Jan 18 '17 at 03:38
  • 1
    @Sobhan, yes there is a difference. The switchMap operator returns an Observable while the subscribe operator allows the observer (our component) to see the items ultimately being emitted by an Observable. So in the docs there are 2 instances of switchmap being employed. 1) They've used switchMap to append a request for heros. SwitchMap, unlike subscribe, will ensure that the request is cancelled should the user re-navigate to the route while still retrieving a hero. 2) An async pipe is used. Async pipes consume an observable, so one must not subscribe (The async pipe will do that for you). – Stephen Paul Jan 18 '17 at 04:56
  • I had no luck with `params` but `queryParams` worked for me. So; ` this._activatedRoute.queryParams.subscribe((params: Params) => { console.log(params); }); ` – Richard Oliver Bray Nov 21 '17 at 18:13
  • Your link of unsubscribe is no more working. Would be really interested in. – Mick Aug 01 '19 at 14:56
  • 1
    @richbray89 To specify "Note: Below 'queryParams' can be replaced with 'params' depending on your requirements" a bit further: the parts you specify explicitly in the router, e.g. `/user/:userId` are in the params and "the stuff behind the question mark", e.g. `/user-search?name=albert` is in the query params. – bersling Sep 16 '19 at 15:39
130

When a URL is like this http://stackoverflow.com?param1=value

You can get the param 1 by the following code:

import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router';

@Component({
    selector: '',
    templateUrl: './abc.html',
    styleUrls: ['./abc.less']
})
export class AbcComponent implements OnInit {
    constructor(private route: ActivatedRoute) { }

    ngOnInit() {
        // get param
        let param1 = this.route.snapshot.queryParams["param1"];
    }
}
Trung
  • 1,819
  • 1
  • 13
  • 10
  • 3
    does this mean that you don't need to add the "/:id" in the routeconfig path anymore? because I get "undefined" when I use this so I must still have an error somewhere – Axelle Jan 02 '18 at 22:44
  • 2
    Great. This was I'm looking for because I need to read the params directly from a dynamic server url. I cannot use navigate. – The.Bear May 11 '18 at 15:11
  • 1
    I am not sure why `quearyParams` is `{}` even on `ngOnInit()` I made a change to `this.activatedRoute.queryParams.subscribe((params) => console.log(params))` and it started working fine .. I am not sure if that is right way to do it – rainversion_3 Sep 02 '20 at 21:31
  • Ahh .. I got why it's `undefined`, I previously wasn't using `` as there was a single component. Now I added some routes and checked from snapshot `queryParamMap` is available. Thought it would be helpful to someone in future – rainversion_3 Sep 02 '20 at 21:43
39

Even though the question specifies version beta 7, this question also comes up as top search result on Google for common phrases like angular 2 query parameters. For that reason here's an answer for the newest router (currently in alpha.7).

The way the params are read has changed dramatically. First you need to inject dependency called Router in your constructor parameters like:

constructor(private router: Router) { }

and after that we can subscribe for the query parameters on our ngOnInit method (constructor is okay too, but ngOnInit should be used for testability) like

this.router
  .routerState
  .queryParams
  .subscribe(params => {
    this.selectedId = +params['id'];
  });

In this example we read the query param id from URL like example.com?id=41.

There are still few things to notice:

  1. Accessing property of params like params['id'] always returns a string, and this can be converted to number by prefixing it with +.
  2. The reason why the query params are fetched with observable is that it allows re-using the same component instance instead of loading a new one. Each time query param is changed, it will cause a new event that we have subscribed for and thus we can react on changes accordingly.
Roope Hakulinen
  • 7,326
  • 4
  • 43
  • 66
  • Is there a way to have multiple parameters going to the same member? For example, I would like either 'id' or 'identification' to go to this.selectedId. – phandinhlan Jul 11 '16 at 20:49
  • @phandinhlan: Well, that isn't really a question related to Angular 2. It can of course be implemented, but you need to define the logic yourself. Basically what you want to do is to first check if the first key is defined and only then read the value from it, and if not, read the value with another key. This could be achieved with something like `if (params.hasOwnProperty('id')) { this.selectedId = params['id'] } else { this.selectedId = params['identification']}`. – Roope Hakulinen Jul 11 '16 at 20:59
  • Yea I ended up doing something like that. I just thought there would be some "built in" way like: this.selectedId = +params['id']; this.selectedId = +params['identification']; Of course that doesn't make any sense and doesn't work. – phandinhlan Jul 11 '16 at 21:02
30

I really liked @StevePaul's answer but we can do the same without extraneous subscribe/unsubscribe call.

import { ActivatedRoute } from '@angular/router';
constructor(private activatedRoute: ActivatedRoute) {
    let params: any = this.activatedRoute.snapshot.params;
    console.log(params.id);
    // or shortcut Type Casting
    // (<any> this.activatedRoute.snapshot.params).id
}
codef0rmer
  • 10,284
  • 9
  • 53
  • 76
  • 7
    the caveat of course with this one is that it will be the initial value and subsequent changes won't be reflected. So if you're changing the URL parameters programmatically as part of your logic that's something you need to be aware of – ambidexterous Aug 25 '17 at 20:50
  • Not sure if this changed with later versions of Angular, but I now see it in this.activatedRoute.snapshot.queryParams – Michael Dec 12 '18 at 18:39
  • For me `this.activatedRoute.snapshot.queryParams` worked! – Arash Feb 23 '22 at 13:50
24

To send query params

import { Router } from '@angular/router';
this.router.navigate([ '/your-route' ], { queryParams: { key: va1, keyN: valN } });

To receive query params

import { ActivatedRoute } from '@angular/router';
this.activatedRoute.queryParams.subscribe(params => {
    let value_1 = params['key'];
    let value_N = params['keyN'];
});

Official source

Community
  • 1
  • 1
dddenis
  • 480
  • 1
  • 8
  • 14
15

Hi you can use URLSearchParams, you can read more about it here.

import:

import {URLSearchParams} from "@angular/http";

and function:

getParam(){
  let params = new URLSearchParams(window.location.search);
  let someParam = params.get('someParam');
  return someParam;
}

Notice: It's not supported by all platforms and seems to be in "EXPERIMENTAL" state by angular docs

Asaf Hananel
  • 7,092
  • 4
  • 24
  • 24
  • 2
    This doesn't work for me. I've found that window.location.search includes the leading question mark of the querystring parameters. So, the key for the first parameter will have the question mark prepended. – AJ Morris Feb 27 '17 at 19:28
  • AJ Morris, to get around your issue: `if (window.location.search.indexOf('?') == 0){ normalizedQueryString = window.location.search.substring(1); } else { normalizedQueryString = window.location.search; } let params = new URLSearchParams(normalizedQueryString);` – ambidexterous Aug 25 '17 at 20:38
  • URLSearchParams it's deprecated. Now you can do it with ActivatedRoute. – Robert Blasco Villarroya Nov 07 '18 at 15:27
10

Get URL param as an object.

import { Router } from '@angular/router';
constructor(private router: Router) {
    console.log(router.parseUrl(router.url));
}
Jsonras
  • 1,120
  • 13
  • 10
7

You can get the query parameters when passed in URL using ActivatedRoute as stated below:-

url:- http:/domain.com?test=abc

import { Component } from '@angular/core';
import { ActivatedRoute }     from '@angular/router';

@Component({
  selector: 'my-home'
})
export class HomeComponent {

  constructor(private sharedServices : SharedService,private route: ActivatedRoute) { 
    route.queryParams.subscribe(
      data => console.log('queryParams', data['test']));
  }

}
Saurabh
  • 449
  • 4
  • 7
6

First off, what I have found working with Angular2 is that the url with a query string would be /path;query=value1

To access it in a component you use

constructor(params: RouteParams){
    var val = params.get("query");
}

As to why it would be removed when you load the component, that isn't default behavior. I checked specificly in a clean test project and wasn't redirected or changed. Is it a default route or something else that is special about the routing?

Read about routing with query strings and params in the Angular2 Tutorial at https://angular.io/docs/ts/latest/guide/router.html#!#query-parameters

Dharman
  • 30,962
  • 25
  • 85
  • 135
Namirna
  • 402
  • 2
  • 12
  • I cant use params like ";param1=value1;param2=value2", this link generated on another site and redirect on my site like "example.com/auth?code_for_auth=askjfbkajdsbfksajdf" – FireGM Feb 28 '16 at 22:21
  • The way the routing is set up in Angular2 at the moment, I don't think it is possible really. Some sort of workaround is going to be needed since child routing does depend on matrix url. As for as I know at least. I would intercept it at my webserver and transform them as a hack, sucks but I can't think of another way at the moment – Namirna Feb 29 '16 at 11:52
  • You don't have the possibility of asking the linking site to change their url? – Namirna Feb 29 '16 at 11:53
  • 1
    No. But I solved the problem simply manually parse Location.path () – FireGM Feb 29 '16 at 14:30
  • 4
    this solution deprecated! –  Jul 13 '16 at 13:30
4

I hope it will help someone else.

Question above states that query param value is needed after page has been redirected and we can assume that snapshot value (the no-observable alternative) would be sufficient.

No one here mentioned about snapshot.paramMap.get from the official documentation.

this.route.snapshot.paramMap.get('id')

So before sending it add this in sending/re-directing component:

import { Router } from '@angular/router';

then re-direct as either (documented here):

this.router.navigate(['/heroes', { id: heroId, foo: 'foo' }]);

or simply:

this.router.navigate(['/heroes', heroId ]);

Make sure you have added this in your routing module as documented here:

 { path: 'hero/:id', component: HeroDetailComponent }

And finally, in your component which needs to use the query param

  • add imports (documented here):

    import { Router, ActivatedRoute, ParamMap } from '@angular/router';
    
  • inject ActivatedRoute

( documentation also imports switchMap and also injects Router and HeroService - but they are needed for observable alternative only - they are NOT needed when you use snapshot alternative as in our case ):

    constructor(
      private route: ActivatedRoute
    ) {}
  • and get the value you need ( documented here):

    ngOnInit() {
      const id = this.route.snapshot.paramMap.get('id');
    }
    

NOTE: IF YOU ADD ROUTING-MODULE TO A FEATURE MODULE (AS SHOWN IN DOCUMENTATION) MAKE SURE THAT IN APP.MODULE.ts THAT ROUTING MODULE COMES BEFORE AppRoutingModule (or other file with root-level app routes) IN IMPORTS: [] . OTHERWISE FEATURE ROUTES WILL NOT BE FOUND (AS THEY WOULD COME AFTER { path: '**', redirectTo: '/not-found' } and you would see only not-found message).

Ula
  • 2,628
  • 2
  • 24
  • 33
3

now it is:

this.activatedRoute.queryParams.subscribe((params: Params) => {
  console.log(params);
});
Alan
  • 9,167
  • 4
  • 52
  • 70
  • 1
    Thank you for this code snippet, which might provide some limited short-term help. A proper explanation [would greatly improve](https://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) its long-term value by showing why this is a good solution to the problem and would make it more useful to future readers with other, similar questions. Please edit your answer to add some explanation, including the assumptions you've made – Shawn C. Mar 06 '18 at 21:34
2

If you only want to get query parameter once, the best way is to use take method so you do not need to worry about unsubscription. Here is the simple snippet:-

constructor(private route: ActivatedRoute) {
  route.snapshot.queryParamMap.take(1).subscribe(params => {
     let category = params.get('category')
     console.log(category);
  })
}

Note: Remove take(1) if you want to use parameter values in future.

1

You just need to inject ActivatedRoute in constructor and then just access params or queryParams over it

constructor(private route:ActivatedRoute){}
ngOnInit(){
        this.route.queryParams.subscribe(params=>{
        let username=params['username'];
      });
 }

In Some cases it doesn't give anything in NgOnInit ...maybe because of init call before initialization of params in this case you can achieve this by asking observable to wait for some time by function debounceTime(1000)

e.g=>

 constructor(private route:ActivatedRoute){}
    ngOnInit(){
            this.route.queryParams.debounceTime(100).subscribe(params=>{
            let username=params['username'];
          });
     }

debounceTime() Emits a value from source observable only after particular time span passed without another source emission

Salman Ahmed
  • 682
  • 1
  • 10
  • 24
Rajiv
  • 1,245
  • 14
  • 28
0

Query and Path (Angular 8)

If you have url like https://myapp.com/owner/123/show?height=23 then use

combineLatest( [this.route.paramMap, this.route.queryParamMap] )
  .subscribe( ([pathParams, queryParams]) => {
    let ownerId = pathParams.get('ownerId');    // =123
    let height  = queryParams.get('height');    // =height
    // ...
  })

UPDATE

In case when you use this.router.navigate([yourUrl]); and your query parameters are embedded in yourUrl string then angular encodes a URL and you get something like this https://myapp.com/owner/123/show%3Fheight%323 - and above solution will give wrong result (queryParams will be empty, and query params can be glued to last path param if it is on the path end). In this case change the way of navigation to this

this.router.navigateByUrl(yourUrl);
Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
0

My old school solution:

queryParams(): Map<String, String> {
  var pairs = location.search.replace("?", "").split("&")
  var params = new Map<String, String>()
  pairs.map(x => {
    var pair = x.split("=")
    if (pair.length == 2) {
      params.set(pair[0], pair[1])
    }
  })

  return params
}
Alexandr
  • 695
  • 2
  • 9
  • 18
0

ANGULAR 16 UPDATE

In Angular 16 you can now listen to router params using @Input bindings:

@RouterInput() myUrlParam!: string;

or

@Input() myUrlParam!: string;

so if your URL is like /myapp/main-component?myUrlParam=helloworld

it will set 'helloworld' value to MainComponent's myUrlParam Input.

More info

Pedro Bezanilla
  • 1,167
  • 14
  • 22
-2

You cannot get a parameter from the RouterState if it's not defined in the route, so in your example, you have to parse the querystring...

Here is the code I used:

let re = /[?&]([^=#&]+)=([^&#]*)/g;
let match;
let isMatch = true;
let matches = [];
while (isMatch) {
    match = re.exec(window.location.href);
    if (match !== null) {
        matches[decodeURIComponent(match[1])] = decodeURIComponent(match[2]);
        if (match.index === re.lastIndex) {
            re.lastIndex++;
        }
    }
    else {
        isMatch = false;
    }
}
console.log(matches);
Julien Ricard
  • 316
  • 2
  • 11