I want to share a value between all my components (which are not necessarily related) using a service.
There are a number of examples online but it doesn't work for me, I don't know what I did wrong.
Also, many examples are based on old versions of Angular whereas I would like to use modern methods to do it.
For now I have this 3 files, and I want to share a "Theme" value :
theme.service.ts :
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class ThemeService {
private _theme: 'light'|'dark' = 'light';
public get Theme() {
return this._theme;
}
public set Theme(theme: 'light'|'dark') {
this._theme = theme;
}
constructor() { }
}
app.component.ts :
import { Component, AfterViewInit } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { ThemeService } from './services/theme.service';
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet],
providers: [ThemeService],
templateUrl: './app.component.html',
styleUrl: './app.component.scss'
})
export class AppComponent implements AfterViewInit {
constructor(private themeService: ThemeService) { }
ngAfterViewInit() {
console.log("app.component:", this.themeService.Theme);
this.themeService.Theme = "dark";
console.log("app.component:", this.themeService.Theme);
}
}
mycomponent.component.ts :
import { Component, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
import { ThemeService } from '../../services/theme.service';
@Component({
selector: 'app-mycomponent',
standalone: true,
imports: [],
providers: [ThemeService],
templateUrl: './mycomponent.component.html',
styleUrl: './mycomponent.component.scss'
})
export class MyComponent implements AfterViewInit {
constructor(private themeService: ThemeService) { }
ngAfterViewInit() {
console.log("mycomponent.component:", this.themeService.Theme);
}
}
I would like to have this result:
app.component: light
app.component: dark
mycomponent.component: dark
But I have this:
app.component: light
app.component: dark
mycomponent.component: light
I imagine that the two components are using different instances of the service, how do I make it so that the service is shared between the two?
Don't add ThemeService
to your components' providers
arrays. The service is already providedIn: 'root'
which means you already have a singleton for the application. If you add the service to the providers
array for the component, you'll create a second copy that only that component knows about.
See the Dependency injection and injectors hierarchy section of the Getting started with standalone components guide (emphasis mine):
Angular applications can configure dependency injection by specifying a set of available providers. In a typical application, there are two different injector types:
- module injector with providers configured in
@NgModule.providers
or@Injectable({providedIn: "..."})
. Those application-wide providers are visible to all components in as well as to other services configured in a module injector.- node injectors configured in
@Directive.providers
/@Component.providers
or@Component.viewProviders
. Those providers are visible to a given component and all its children only.