Home > Net >  How can I defer resolution of a dependency in the injector?
How can I defer resolution of a dependency in the injector?

Time:03-18

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?

CodePudding user response:

I see an issue from the get go.

<my-component config="someConfig"></my-component>

this would bind the string "someConfig"

It should be:

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

this would bind the variable someConfig from the holding component component.

for the injection stuff. I dont see you need injection if you have someConfig available already but just passes it into my-component

Edit: For the service you have 3 levels you can provide it. On Root, Module and Component level

for modules and components its done the same way.

@Component({
    selecter : 'my-component',
    ...
    providers: [ MyService ]
})
export class MyComponent { ... }

Now you might want to use a factory or something like that to parse the extra value. Or you could have create a injection token which you set in the providers instead. relevant source for how to: https://angular.io/guide/dependency-injection-providers

CodePudding user response:

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) {
  }
}
  • Related