Problem with Angular singleton, or so I thought?

Published by

on

The issue was that in my singleton service constructor, I am creating dummy data that I want to use in the app. As I was setting up routing, when navigating to each route, the constructor would re-run, and in my case, none of the id’s that were created (uuid4) remained valid.

In the documentation, which can be found here can be found here: https://angular.io/guide/architecture-services, it states:

When you provide the service at the root level, Angular creates a single, shared instance of HeroService and injects it into any class that asks for it. Registering the provider in the @Injectable() metadata also allows Angular to optimize an app by removing the service from the compiled application if it isn't used, a process known as tree-shaking.

This is what I thought I was doing, I wanted a singleton that could be injected anywhere and be reused. But just below you see the following:

When you register a provider at the component level, you get a new instance of the service with each new instance of that component. At the component level, register a service provider in the providers property of the @Component() metadata.

This is not want I want but was in fact what I was experiencing.

But again, according to the doc, if I decorated the service like this (which I was doing)

@Injectable({
  providedIn: 'root'
})

Angular would ensure this was a singleton. Just in case, I made sure to remove the service from the provider statement in each component but I was still getting the same result, the constructor was still running after each route. But based on the documentation, I felt I was doing everything correctly and was growing increasingly frustrated. That’s when I came across the following issue:

https://github.com/angular/angular/issues/45232

Turns out, the singleton was not my issue at all. I was using the normal href in my <a> tags for links. In my opinion it is not very clear in the docs but if you follow the tutorial they do discuss this. Since this is a single page app, traditional links/routing are not in play. Each time I was hitting an href link, apparently Angular considers that a reload. So naturally as the app reloaded the constructor would run again, which now makes total sense.

I lost about an hour staring at my code and the doc knowing that I was doing what it said and the issue turned out to be something totally different. I am very grateful for the github issue because I do not think I would have thought of that on my own.

Great, problem solved….

I then switched all href statements to routerLink, but nothing happened, they did not render as links :(. For something that trivial I though would be included in the core module, but as it turns out, each component using routerLink will need to import RouterModule. Being new to Angular, I am still getting used to all of these imports.

If you get the ‘Can’t bind to ‘routerLink’ since it isn’t a known property’ message, just import RouterModule.

Links, routes and singletons are now all working as expected.

Angular documentation/tutorial for routing:
https://angular.io/api/router
https://angular.io/guide/router-tutorial-toh#milestone-2-routing-module