1

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.

stackblitz

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

enter image description here

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

3
  • So, if I understood correctly, you want to have HoverService declared once, imported in two different modules and have two separate instances for each module, correct? If yes, I believe this is currently not implementable. Commented Oct 30, 2023 at 22:27
  • If you want to have a separate instance of service at the component level, you could set the provider to your component via the @Component decorator Commented Oct 31, 2023 at 5:41
  • I forked your stackblitz and made some change in the components to use a new instance of HoverService in your component. stackblitz.com/edit/… Commented Oct 31, 2023 at 5:46

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.