7

I have created a new module in my app so I can separate parts that do not have to communicate and created an new.module.ts with its own routing module and components :

new-routing.module.ts:

const exportRoutes: Routes = [
  {
    path: 'export',
    component: ExportsComponent
  }
]

@NgModule({
  imports: [RouterModule.forRoot(exportRoutes)],
  exports: [RouterModule]
})
export class ExportRoutingModule {}

new.module.ts:

import { Router } from '@angular/router'
import { BrowserModule } from '@angular/platform-browser'

// Routing Module
import { NewRoutingModule } from './new-routing.module'

@NgModule({
  imports: [..., ExportRoutingModule, ...],
  declarations: [ExportsComponent],
  bootstrap: [ExportsComponent]
})

I have a simple index.html:

<body class="app">
  <router-outlet></router-outlet> // outlet is here because I read that I needed it to be able to use activated route, I actually just want the query params
</body>

and finally, where the problem lies, my component :

export class MyComponent implements OnInit {

constructor(private activatedRoute: ActivatedRoute) {}

ngOnInit() {this.activatedRoute.queryParamMap.subscribe(
(params: ParamMap) => console.log(params) 
// Do stuff with params => error)}

When I navigate to http://localhost:4200/export?firstParam=1.00,2.00,3.00 in my console, the params are logued twice, once empty, once populated as such :

ParamsAsMap {params: {…}}
keys:(...) // empty
params:{} // empty

core.js:3565 Angular is running in the development mode. Call enableProdMode() to enable the production mode.

ParamsAsMap {params: {…}}
keys:Array(3)
params:{firstParam: "1.00,2.00,3.00", secondParam: "bla"}

This cause my component to throw error since I need those params to display my component and the first time they are logued they are empty so :

  • Why are they loggued twice ?
  • Why is my code executed before my params observable has a value ?
  • Could I get rid of the router outlet (which I don't really need since I have no routing involved with this module, I just used it because I read that I couldn't use activatedRoute without it; I just want the query params from my url

Thanks for your help

Jota.Toledo
  • 27,293
  • 11
  • 59
  • 73
Lakston
  • 868
  • 7
  • 21

4 Answers4

5

I'll offer 2 solutions to this problem, first, using the skip operator :

Since Activated Route is a BehaviorSubject so first we'll get an empty value, then the actual queryparams so we can skip the first value :

(note, this solution uses lettable operators, hence the pipe(), if you are not using lettable operators you can just chain it like you would do any other rxjs operators : .skip(1)

export class MyComponent implements OnInit {

  constructor(private activatedRoute: ActivatedRoute) {}

  ngOnInit() 
    {this.activatedRoute.queryParamMap.pipe(skip(1)).subscribe(
    (params: ParamMap) => console.log(params)}

Second solution, use a regular javascript function to retrieve the params :

ngOnInit() {
  const token = this.getParameterByName('access_token');
  console.log(token);
}

getParameterByName(name: any) {
  let url = window.location.href;
  name = name.replace(/[[]]/g, "\$&");
  var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
  results = regex.exec(url);
  if (!results) return null;
  if (!results[2]) return '';
  return decodeURIComponent(results[2].replace(/+/g, " "));
}

I'll point you to this stackoverflow answer for the original code

Lakston
  • 868
  • 7
  • 21
1

The accepted answer by @Lakston does not take into account the flow when there's no query params and we need to detect it. After struggling a lot I found a real solution for those of us working with SSR (Server Side Rendering, meaning no browser global objects available for us) and in need of detecting the no query param scenario.

import { Location } from '@angular/common';
----------------------------------------------------------
constructor(private location: Location)
----------------------------------------------------------
let questionIndex = this.location.path().indexOf('?');
questionIndex = questionIndex === -1 ? Infinity : questionIndex;
const queryParams = (<any>Object).fromEntries(this.location.path().substr(questionIndex + 1).split('&').filter(str => str).map(el => el.split('=')));

All credits to YugasVasyl, who posted this answer on: https://github.com/angular/angular/issues/12157

I already test it on my project and it works! Blessings...

Ramiro G.M.
  • 357
  • 4
  • 7
0

I think the issue is that you are using the ExportsComponent for bootstrapping:

@NgModule({
  ...
  bootstrap: [ExportsComponent]
})

The component you specify here is used when the application starts, so it's ngOnInit is called early.

What you can do is to have a separate component for bootstrapping and separate ExportComponent, here is an example (see the live version):

import { bootstrap } from '@angular/platform-browser-dynamic';
import { RouterModule, Router, Routes, ActivatedRoute } from '@angular/router';
import { NgModule, Component, OnInit }       from '@angular/core';
import { BrowserModule }  from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

@Component({
    selector: 'my-app',
    template: `
    <nav class="rbe-plunk-nav">
      <ul>
        <li> <a [routerLink]="['/']">Homepage</a> </li>
        <li> <a [routerLink]="['/about']">Export</a> </li>
      </ul>
    </nav>

    <main>
      <router-outlet></router-outlet>
      <!-- The router will put the content here, right after the outlet -->
    </main>
  `
})
export class AppComponent { }

@Component({
  selector: 'home',
  template: '<h1>Home: </h1>'
})
export class HomeComponent { }

@Component({
  selector: 'export',
  template: '<h1>Export: </h1>'
})
export class ExportComponent implements OnInit {

  constructor(private route: ActivatedRoute) {}

  ngOnInit() {
     this.route.queryParamMap.subscribe(paramMap => {
         console.log("Export: ");
         console.log(paramMap);
     });
  }
}

export const routes: Routes = [
  { path: '',         component: HomeComponent },
  { path: 'about',    component: ExportComponent }
];

@NgModule({
  imports: [
    BrowserModule,
    RouterModule.forRoot(
      routes,
      { /*enableTracing: true*/ }
    )
  ],
  declarations: [
    AppComponent,
    HomeComponent,
    ExportComponent
  ],
  bootstrap: [ AppComponent ]
})
export class AppModule {
  // Diagnostic only: inspect router configuration
  constructor(router: Router) {
    console.log('Routes: ', JSON.stringify(router.config, undefined, 2));
  }
}

platformBrowserDynamic().bootstrapModule(AppModule);
Borys Serebrov
  • 15,636
  • 2
  • 38
  • 54
  • Hey, thanks for taking the time to answer ! I've actually found two working solutions to the empty params problem, I posted an answer to illustrate both of them. – Lakston Dec 04 '17 at 15:44
0

Url: http://localhost:4200/licenca-filtro?param=60&param2=50

component.ts

constructor(
    private route: ActivatedRoute,
  ) {

    const param1 = this.route.queryParams['value']['param'];
    const param2 = this.route.queryParams['value']['param2'];
    
    console.log(param1, param2);

   }

OUT: 60 50