4

I'm using the ActivatedRoute to get a parameter from my route in an injected service. If I specify the service as a provider in the app module or app component the param map is empty when it gets called. If I specify it as a provider in the component that pulls in the service it has the parameter.

Why is this working this way. I've had trouble finding good information on how the ActivatedRoute is scoped and how it interacts with services.

Link to this behavior in plnkr. Uncomment line 11 (providers field) in a.component.ts to see it working when you click me! https://plnkr.co/edit/3U9dZm9fdUlG6KW3GyoQ

import {Component, OnInit} from '@angular/core'
import {AService} from './a.service.ts'

@Component({
  selector: 'app-a',
  template: `
    <div>
      <h2>Hello {{id}}</h2>
    </div>
  `,
//  providers: [AService]
})
export class AComponent implements OnInit {
  id: string;

  constructor(private aService: AService) {

  }

  ngOnInit() {
    this.id = this.aService.getId();
  }
}
Brian
  • 2,253
  • 2
  • 23
  • 39
  • 1
    Brian, when you subscribe to ActiveRouter.ParamMap this subscription is about the component where you make the subscription. In your case, the param "id" only change when the a.component is showed. If your service is declared in app.ts, there are no params "id" (the path to show your app.ts is "/"). When you declare the service in a-app.ts, is another instance of the service, and it is the reason because in this case you have "id" param. – Eliseo Mar 19 '18 at 19:36
  • 1
    Imagine you have a parent "home" and two childs "home/detail/:id" and "home/list/:id", you must subscribe to the activeRouter.paramMap in the two child because "home" have no param "id" – Eliseo Mar 19 '18 at 19:36

1 Answers1

4

The behavior you are seeing is due to the nature of the paramMap member in ActivatedRoutes. In your service constructor you subscribe to the paramMap

constructor(private activatedRoute: ActivatedRoute) {
    this.activatedRoute.paramMap.subscribe(
      params => {
        this.id = params.get('id');
      }
    );
  } 

Which results in a SnapShot view of the route for it's associated component. At that point since you declared the a.service.ts as a provider of your root module app.module.ts the snapshot of the route will contain no :id, because the component it is associated with is your app.component.ts. Therefore when you call your method

getId(): string {
    return this.id;
  }

from your component you're receiving the initial snapshot of the route which is associated with app.component.ts and will not contain a value.

However, when you declare a.service.ts as a provider of the component a.component.ts you then have created a new local instance of a.service.ts' In this scenario the subscription made to paramMap is associated with a.component.ts and the snapshot of that components route does contain an :id param and therefore is returned to you when calling getid().

From the Angular source code:

export class ActivatedRoute {
     /** The current snapshot of this route */
       _paramMap: Observable<ParamMap>;
    ...}

>

Narm
  • 10,677
  • 5
  • 41
  • 54