[typescript] How to get query params from url in Angular 2?

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

This question is related to typescript angular

The answer is


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"];
    }
}

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


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:

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


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.

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.


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
}

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
}

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']));
  }

}

Get URL param as an object.

import { Router } from '@angular/router';
constructor(private router: Router) {
    console.log(router.parseUrl(router.url));
}

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 So is this, but now follows a code block:

    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


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

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


now it is:

this.activatedRoute.queryParams.subscribe((params: Params) => {
  console.log(params);
});

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


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


Examples related to typescript

TS1086: An accessor cannot be declared in ambient context Element implicitly has an 'any' type because expression of type 'string' can't be used to index Angular @ViewChild() error: Expected 2 arguments, but got 1 Typescript: No index signature with a parameter of type 'string' was found on type '{ "A": string; } Understanding esModuleInterop in tsconfig file How can I solve the error 'TS2532: Object is possibly 'undefined'? Typescript: Type 'string | undefined' is not assignable to type 'string' Typescript: Type X is missing the following properties from type Y length, pop, push, concat, and 26 more. [2740] Can't perform a React state update on an unmounted component TypeScript and React - children type?

Examples related to angular

error NG6002: Appears in the NgModule.imports of AppModule, but could not be resolved to an NgModule class error TS1086: An accessor cannot be declared in an ambient context in Angular 9 TS1086: An accessor cannot be declared in ambient context @angular/material/index.d.ts' is not a module Why powershell does not run Angular commands? error: This is probably not a problem with npm. There is likely additional logging output above Angular @ViewChild() error: Expected 2 arguments, but got 1 Schema validation failed with the following errors: Data path ".builders['app-shell']" should have required property 'class' Access blocked by CORS policy: Response to preflight request doesn't pass access control check origin 'http://localhost:4200' has been blocked by CORS policy in Angular7