How can I provide a service that is not at the root of the application, and use the same instance between several components and other services? Not using providers in routes and not using ng module.
I’ve tried Environment injector, but didn’t get any result
6
You can create a Singleton pattern to create a class
Imagine a simple service
@Injectable()
export class DataService {
count:number=0;
constructor(private httpClient:HttpClient){}
getData()
{
return this.httpClient.get('assets/data.json')
}
}
We can to have a class ServiceFactory
export class ServiceFactory
{
private static instance:DataService
public static create(httpClient: HttpClient)
{
if (!this.instance)
this.instance=new DataService(httpClient)
return this.instance;
}
}
See that have a property dataService create as new DataService(httpClient) and the component not inject the data service else use serviceFactory.create() and a getter dataService that will be the serviceFactory.dataService
We can use this ServiceFactory to give value to a variable dataService in the way
@Component({
selector: 'one',
standalone: true,
imports:[JsonPipe],
template: `
<h1>one</h1>
<button (click)="dataService.count=dataService.count+1">
{{dataService.count}}
</button>
<button (click)="click()">getHttp</button>
{{result|json}}
`,
})
export class One {
serviceFactory!:ServiceFactory
result:any;
constructor(httpClient:HttpClient)
{
this.serviceFactory=ServiceFactory.create(httpClient)
}
get dataService()
{
return this.serviceFactory.dataService
}
export class One {
dataService!:DataService
constructor(httpClient:HttpClient)
{
this.dataService=ServiceFactory.create(httpClient);
}
click(){
this.dataService.getData().subscribe({
next:(res:any)=>this.result=res,
error:()=>console.log("error")
})
}
}
Another component that use the same share the “serviceFactory” and the dataService of the serviceFactory.
One component like
@Component({
selector: 'three',
standalone: true,
template: `...`,
providers:[DataService]
})
export class Three {
result:any;
constructor(public dataService:DataService){}
}
have his own instance of the service
I know it’s a bit work-around, but this is the stackblitz
UPDATE a more Angular way
If we create a function dataServiceProvider
export const dataServiceProvider = (httpClient:HttpClient)=>
ServiceFactory.create(httpClient);
We can use provider with useFactory, so our componets like:
@Component({
selector: 'one',
standalone: true,
imports:[JsonPipe],
template: `...`,
providers:[{provide:DataService,useFactory:dataServiceProvider,
deps:[HttpClient]}]
})
export class One {
//we inject in constructor
constructor(public dataService:DataService){}
}
a new stackblitz