[SOLVED] How can I defer resolution of a dependency in the injector?

Issue

I would like to resolve a configuration object for the injector when ngOnInit is called.

This is what I am trying to do:

<my-component [config]="someConfig"></my-component>
// my.component.ts

import { CONFIG_TOKEN } from 'injector_tokens';

@Component({
  selector: 'my-component',
  template: '<p>need to delay dependency injector resolution... but how?! it's not in the docs...</p>',
  styleUrls: [],
  providers: [
    SomeService
  ]
})
export class MyComponent implements OnInit {
  @Input() config: Config;
  ngOnInit(): void {
    // I want to be able to now add to the injector's providers array: 
    // { provide: CONFIG_TOKEN, useValue: this.config }
    // how can I do that?
  }

}
// some_service.ts

import { CONFIG_TOKEN } from 'injector_tokens';

export class SomeService {
  constructor(@Inject(CONFIG_TOKEN) config: Config) {
    // config should be the config object passed in via html attribute
  }
}

How can I do it?

Solution

Well, it’ usually an anti-pattern, but I see the use. Basically you have a config which comes to the component via template, but the config is also for the service instance underlying the component’s business logic.

Seems fair.

I think your best bet is to trade the construction-time usability of your service (usually a nice characteristic) with an Init(config: Config) method, to be called inside the ngOnInit method of your component. In this way, you keep the Dependency Injection provided parameters in the service constructor, you keep the providers definition in your component easy peasy, and there is no direct usage of the injector.

If you want, you could even call the SomeService.Init method in the setter of the component’s input property:

@Component({
  selector: 'my-component',
  template: '<p>whatever...</p>',
  styleUrls: [],
  providers: [ SomeService ]
})
export class MyComponent {

  private _config: Config = null;
  @Input() get config(): Config {
    return _config;
  }
  set config(v: Config) {
    _config = v;
    this.someService.Init(v);
  }

  constructor(Self() private someService: SomeService) {
  }
}

Answered By – A. Chiesa

Answer Checked By – Timothy Miller (BugsFixing Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *