angulartypescriptangular-routingangular-routerangular-router-params

Unable to read querystring parameters from App.Component


I would like to centralize where/how I read a specific querystring parameter throughout my application, so I figured the best place to do this was in the app.component.ts

export class AppComponent implements OnInit, OnDestroy {
  constructor(
    private router: Router,
    private activatedRoute: ActivatedRoute) {
  }

Then, on ngOnInit(), I am looking in the snapshot as well as different subscriptions:

  ngOnInit(): void {
    console.log('AppComponent - ngOnInit() -- Snapshot Params: ' + this.activatedRoute.snapshot.params['code']);
    console.log('AppComponent - ngOnInit() -- Snapshot Query Params: ' + this.activatedRoute.snapshot.queryParams['code']);
    console.log('AppComponent - ngOnInit() -- Snapshot Query ParamMap: ' + this.activatedRoute.snapshot.queryParamMap.get('code'));

    this.activatedRouteParamsSubscription = this.activatedRoute.params.subscribe(params => {
      console.log('AppComponent - ngOnInit() -- Subscription Params: ' + params['code']);
    });

    this.activatedRouteQueryParamsSubscription = this.activatedRoute.queryParams.subscribe(params => {
      console.log('AppComponent - ngOnInit() -- Subscription Query Params: ' + params['code']);
    });

    this.activatedRoute.queryParamMap.subscribe(queryParams  => {
      console.log('AppComponent - ngOnInit() -- Subscription Query ParamMap: ' + queryParams.get('code'));
    });

    this.routerEventsSubscription = this.router.events.subscribe(event => {
      if (event instanceof NavigationEnd) {
        console.log('AppComponent - ngOnInit() -- Subscription NavigationEnd: URL=', event.url);
      }
    });
  }

As you can see, I've set up a subscription for params, queryParams, queryParamMap and router.events.

The only one that fires between page navigations is the router.events, but there, I would have to manually parse the URL to get the query string.

Not sure if this has any effect on it, but I'm overriding the route reuse strategy so the page is reloaded even if it is on the same route:

export class AppRoutingModule {
  constructor(private router: Router) {
    this.router.routeReuseStrategy.shouldReuseRoute = function() {
        return false;
    };
  }
}

Output of root page on first visit:

AppComponent - constructor() -- Snapshot Params: undefined
AppComponent - constructor() -- Snapshot Query Params: undefined
AppComponent - ngOnInit() -- Snapshot Params: undefined
AppComponent - ngOnInit() -- Snapshot Query Params: undefined
AppComponent - ngOnInit() -- Snapshot Query ParamMap: null
AppComponent - ngOnInit() -- Subscription Params: undefined
AppComponent - ngOnInit() -- Subscription Query Params: undefined
AppComponent - ngOnInit() -- Subscription Query ParamMap: null
AppComponent - ngOnInit() -- Subscription NavigationEnd: URL= /?code=logged-out

SOLUTION

As both @Thomaz and @Nathan pointed out, my issue was that the App.Component was not inside the router-outlet.

Moreover, @Nathan also pointed out that:

You can access Router events and iterate over them wherever you want in the app though, which is why your router.events.subscribe(...) triggers.

I then enabled tracing on my routes:

RouterModule.forRoot(routes, { onSameUrlNavigation: 'reload', enableTracing: true })

And saw that the ActivationEnd event included a snapshot which had the queryParams. In the end, I'm subscribing to router event and processing my querystring value if the event is ActivationEnd.

this.router.events.subscribe(event => {
      if(event instanceof ActivationEnd) {
        const code = event.snapshot.queryParams['code'];
        if (code) {
          // handle it...
        }
      }
}

Solution

  • ActivatedRoute can be subscribed to from components that are loaded via router-outlet. Since AppComponent is not loaded via any outlet, you cannot subscribe to ActivatedRoute params within it. The re-use strategy is not impacting this.

    From the docs https://angular.io/api/router/ActivatedRoute we know the following:

    [ActivatedRoute] Contains the information about a route associated with a component loaded in an outlet.

    There is no outlet loading AppComponent, so your subscribes won't fire. You can access Router events and iterate over them wherever you want in the app though, which is why your router.events.subscribe(...) triggers.