I have a scenario where I want to share a service within a NgModule
. but at the same time I want to keep its instances usage separate.
in the stackblitz, you can see that I have a hover-report\hover-report.module.ts
. in this module I have two component and one service that is shared between them.
HoverReportComponent
show hover box.
HoverSectionComponent
show the number of times I hovered over the box.
HoverService
keep the count of number of times I hovered over the box.
hover.module.ts:
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HoverReportComponent } from './hover-report.component';
import { HoverSectionComponent } from './hover-section.component';
import { HoverService } from './hover.service';
@NgModule({
declarations: [
HoverReportComponent,
HoverSectionComponent
],
imports: [
CommonModule
],
providers:[
{provide: HoverService, useClass: HoverService}
],
exports:[
HoverReportComponent,
HoverSectionComponent
]
})
export class HoverReportModule { }
hover.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable()
export class HoverService {
private counter = new BehaviorSubject(0);
counter$ = this.counter.asObservable();
addOne() {
console.log('add one' + this.counter.value);
this.counter.next(this.counter.value + 1);
}
}
hover-report.component.ts
import { Component } from '@angular/core';
import { HoverService } from './hover.service';
@Component({
selector: 'app-hover-report',
template: `
{{hoverService.counter$|async}}
`,
styles: [
`
:host {
display: block;
}
`,
],
})
export class HoverReportComponent {
constructor(public hoverService:HoverService) {
}
}
hover-section.component.ts
import { Component } from '@angular/core';
import { HoverService } from './hover.service';
@Component({
selector: 'app-hover-section',
template: ` <div class="hover-me" (mouseover)="onHover($event)"></div> `,
styles: [
`
:host {
display: block;
}
.hover-me{
width:300px;
height:200px;
border: 1px dashed black;
}
`,
],
})
export class HoverSectionComponent {
constructor(private hoverService: HoverService) {}
onHover($event: MouseEvent) {
this.hoverService.addOne();
}
}
then there are two separate modules named RedModule
and BlueModule
that each import HoverReportModule
and use the exported components to render a different variation based on its need.
red.component.ts:
import { Component } from '@angular/core';
@Component({
selector: 'app-red',
template: `
<app-hover-section></app-hover-section>
<h2>
<app-hover-report></app-hover-report>
</h2>
`,
styles: [
`
:host{
display:block;
background-color: #f8ad9d;
padding: 20px;
}
`
]
})
export class RedComponent {
}
blue.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-blue',
template: `
<h2>
<app-hover-report></app-hover-report>
</h2>
<app-hover-section></app-hover-section>
`,
styles: [
`
:host {
display: block;
background-color: #8ecae6;
padding: 20px;
}
`,
],
})
export class BlueComponent {}
the point is, to keep the render components separate so we can use it differently inside a page, based on the design, but at same time, they should behave as one.
my mental model about modules is that a provider is instantiated, at its module level. but apparently I'm missing something.
as you can see even I have two modules (blue and red) each time I hover on one of them, the other one also get updated
so my question is how do I create a service whereby, in a way it is isolated to its usage within RedModule
and BlueModule
but shared within HoverReportModule
.
I don't want to redefine the provider in RedModule
and BlueModule
. I want to encapsulate it within HoverReportModule
so each developer won't be bothered if they forget it
providers:[
{provide: HoverService, useClass: HoverService}
],
my next question would be ... is it convertible to standalone component? at angular standalone component's document suggests to export components that should render together as a const array
export const HoverReport=[ HoverReportComponent, HoverSectionComponent] as const;
but it doesn't talk about how to deal with such cases where the provider should be shared within