1

I have this Config file which has interface for data, default configuration of scrollbar, injection token to be able to inject this configuration and provider for modules that contains factory which returns deepClone of default config object:

export interface ScrollbarConfig {
    name: string;
    class: string;
    options: MCustomScrollbar.CustomScrollbarOptions;
}

export const SCROLLBAR_CONFIG = new InjectionToken<ScrollbarConfig>('scrollbar.config');`

export const SCROLLBAR_CONFIG_DEFAULT: ScrollbarConfig = { ... }

export const SCROLLBAR_CONFIG_PROVIDER = {
    provide: SCROLLBAR_CONFIG,
    useFactory: () => {
            return _.cloneDeep(SCROLLBAR_CONFIG_DEFAULT);
        }
};

This is how add provider to my modules:

providers: [
        SCROLLBAR_CONFIG_PROVIDER
    ]

And that's how I inject it in constructors of my components:

constructor(@Inject(SCROLLBAR_CONFIG) private scrollbarConfig: ScrollbarConfig) {}

So the idea is to get default config of scrollbar and then extend injected object in each component, so each component has own configuration. But for some reason injection gives me same instance even though I use provider with factory. I am pretty sure it makes a deepClone of default object, but then returns this same clonned object for every injection. I also tried to do it with creating class instead of injection token, but it behaved just the same.

I tried putting console.log() in factory function and it printed only once so obviously this is the problem, but how can I force it to really provide different instances?

7
  • Of course, it returns same instance. Providers are singletons (within same injector). The thing that matters here is how this provider is used, the question needs clarification on that. Commented May 31, 2017 at 14:08
  • But I specified in my question that I just pass this provider to providers array in each module Commented May 31, 2017 at 16:02
  • You haven't specified how and where exactly SCROLLBAR_CONFIG is used. This is necessary to give a good answer. Commented May 31, 2017 at 16:12
  • well I just injected that SCROLLBAR_CONFIG in constructors of my components and then simply worked with injected object, I showed basically all I did, so am I missing something? Commented May 31, 2017 at 16:57
  • So SCROLLBAR_CONFIG isn't used by other services, it exists solely to use inside components? Then you should just specify providers: [SCROLLBAR_CONFIG_PROVIDER] for each component where you want to get an instance, not in module. Hierarchical injector works like that. Commented May 31, 2017 at 17:43

1 Answer 1

1

A provider is a singleton within a single injector, and when a service is defined in module providers, it belongs to root injector (or to child injector for lazy-loaded modules).

In order for all components to receive their own instances, providers should be specified for these component classes (and not for module class):

@Component({ ..., providers: SCROLLBAR_CONFIG_PROVIDER }) ...

Since the service is never supposed to be reused and be a singleton, it can be a class defined as useValue provider instead:

export class ScrollbarConfig {
  name: string = ...;
  class: string = ...;
  // or
  // constructor() {
  //   return _.cloneDeep(SCROLLBAR_CONFIG_DEFAULT)
  // }
}

@Module({ ..., providers: { provide: ScrollbarConfig, useValue: ScrollbarConfig }) ...

@Component(...)
class SomeComponent {
  scrollbarConfig: ScrollbarConfig;

  constructor(@Inject(ScrollbarConfig) ScrollbarConfig: typeof ScrollbarConfig) {
    this.scrollbarConfig = new ScrollbarConfig();
  }
}
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.