angularinheritanceservicesingletonextend

Service in Angular is instantiated twice when extending the service with another service


In my Angular project, I have a setup with multiple services. One service has some functions for which I want to restrict access, so that it can only be used from one specific other service.

To achieve this, I want to extend the service in the calling service, and use the protected access modifier to restrict access. However, upon implementing this, I see that the parent service has two instances when I start the application. How can I enforce that the parent service is instantiated only once, as singleton? Or, how should I approach this problem differently to ensure access to the functions in one service are only accesible from the calling service?

The parent service pseudo code:

@Injectable({
  providedIn: 'root'
})
export class ParentService {

  constructor() {
    // below is logged twice!
    console.log('new instance of ParentService created');
  }

  public someFunction() {}

  protected functionIWantToLimitAccessTo() {}

}

The child service pseudo code:

import { ParentService} from './parent.service';

@Injectable({
  providedIn: 'root'
})
export class ChildService extends ParentService {

  constructor() {
    super();  // <- this super() call is needed for class extension
  }

  public publicFunction() {
    super.functionIWantToLimitAccessTo();
  }

}

I would have expected there to be only one instance of ParentService in this setup.


Solution

  • Figured it out.

    By providing the ParentService in app.module.ts instead of in the component itself, I can specify the class I want to inject for the ParentService. I my case, that's the ChildService.

    This way I can inject the ParentService and ChildService everywhere in the application, but I have restricted the access op protected functions of the ParentService to the ChildService only.

    parent service:

    // No longer registered as injectable component here
    // @Injectable({
    //   providedIn: 'root'
    // })
    export abstract class ParentService {
    
      constructor() {
        // below is logged only once now!
        console.log('new instance of ParentService created');
      }
    
      public someFunction() {}
    
      protected functionIWantToLimitAccessTo() {}
    }
    

    child service:

    import { ParentService} from './parent.service';
    
    @Injectable({
      providedIn: 'root'
    })
    export class ChildService extends ParentService {
    
      constructor() {
        super();  // <- this super() call is needed for class extension
    
        // I can call protected function from ParentService from here
        super.functionIWantToLimitAccessTo();
      }
    
        
    }
    

    Usage in component:

    import { ParentService} from './parent.service';
    
    @Injectable({
      providedIn: 'root'
    })
    export class RandomComponent {
    
      constructor(private parentService: ParentService) {
    
        // I can call public functions from ParentService
        this.parentService.someFunction();
    
        // I can NOT call protected function from ParentService here
        this.parentService.functionIWantToLimitAccessTo(); // -> compiler error
      }
    }
    

    And in app.module.ts I have:

    @NgModule({
      providers: [
        { provide: ParentService, useClass: ChildService}
      ]
    })
    export class AppModule { }