4

I'm new to Angular. My goal is to have a BaseDetailComponent which can be extended by "detail" components (those which show a single data object's fields). Since the parent class' constructor will receive a service instance and other params, I can't use normal dependency injection in the constructor. Therefore, I need to manually inject the application injector in BaseDetailComponent. I tried the code below. There is an InjectorManager, which has its injector set by the global AppModule. Then BaseDetailComponent retrieves InjectorManager's injector and uses it to get the app's ActivatedRoute instance. But, for some reason, activatedRoute.snapshot.params.id is undefined. And this is my issue. I need to access route params on a class where ordinary constructor dependency injection is unavailable.

export class InjectorManager {

  private static _injector: Injector;

  static get injector(): Injector {
    return this._injector;
  }

  static set injector(value: Injector) {
    this._injector = value;
  }
}

export class AppModule {

  constructor(
    injector: Injector
  ) {
    InjectorManager.injector = injector;
  }
}

@Component({template: ''})
export class BaseDetailComponent {

  protected activatedRoute: ActivatedRoute;

  constructor(
    private service: BaseService<DtoType>
  ) {
    this.activatedRoute = InjectorManager.injector.get(ActivatedRoute);
  }

  ngOnInit() {

    this.service.findById(this.activatedRoute.snapshot.params.id)
      .subscribe(...);
  }
}

Carlos
  • 43
  • 4

3 Answers3

2

Firs you can inject ActivatedRoute just by placing it in the constructor params.

constructor(
    private service: BaseService<DtoType>,
    protected activatedRoute: ActivatedRoute;
) {}

Second you have to subscribe to this.activatedRoute.params as it can change after the component is initialized:

this.activatedRoute.params.pipe(switchMap(({id}) => this.service.findById(id)).Subscribe(...)
Stanislav Dontsov
  • 1,591
  • 11
  • 24
  • Because BaseDetailComponent is gonna be extended, the constructor cannot have and ActivatedRoute parameter. Otherwise child classes would have to send that, leading to unnecessary repeated code. For some reason, your suggestion (pipe and switchMap over params Observable) is not working. `this.activatedRoute.params .pipe( switchMap((params: Params) => { return this.service.findById(params['id']); })) .subscribe(...` – Carlos Apr 16 '19 at 13:33
  • Are you sure that you need to retrieve route params? Maybe you mean query params? How does your request look like? – Stanislav Dontsov Apr 16 '19 at 14:03
  • Stanisalv, thanks for staying with me against this mistery! My request is an HTTP GET against http://localhost:4200/restaurant-detail/3 . I'm trying to retrieve that "3", but I cannot use regular Angular dependenty injection (constructor parameter) because it's about generic components to be extended. – Carlos Apr 16 '19 at 14:34
  • seems like a route parameter, but what is your routing configuration then? – Stanislav Dontsov Apr 16 '19 at 15:01
2

This is a similar question as Parent components gets empty Params from ActivatedRoute.

The Angular documentation for ActivatedRoute states (my emphasis):

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

There is also an issue of feature request on Angular's GitHub repo asking for a solution, that states (my emphasis):

When using a parametrized route which targets a component, only this component can access those parameters.

Thus, you are encountering an expected behavior. A comment on that issue states that each component receives its own ActivatedRoute (it does not work as singleton like other injected classes).

On that same GitHub issue, the proposed solution is to inject a Router and check for the NavigationEnd events:

router.events.filter(e => e instanceof NavigationEnd).forEach(() => {
  // inspect the state on router.routerState
})

For a complete example check the file src/app.ts on this plunkr provided by @brandonroberts on the GitHub issue: http://plnkr.co/edit/pHd89K?p=preview

Dinei
  • 4,494
  • 4
  • 36
  • 60
0

To get route params subscribe on activatedRoute.params.subscribe((data) => {ur code}) Here the data will contain the params. suppose your registration is path : abc/:id Then the params will conatin id property.

Shilpa J
  • 41
  • 6
  • I tried, but for some reason it does not work. ` this.activatedRoute.params .pipe( switchMap((params: Params) => { return this.service.findById(params['id']); })) .subscribe(` – Carlos Apr 16 '19 at 13:38