0

(I'm sorry that the next paragraph is going to be hard to parse. I find this always happens when describing DI).

I have an existing component, call it Widget.

Widget receives a Thingy via ng2 DI. And Thingy, in turn, receives a ThingyPart via DI.

Now I am writing a new component, call it WidgetList. WidgetList is ultimately going to enter a loop and create multiple Widgets. The main thing that is different about each of these Widgets is that they each need to have a different ThingyPart injected into their Thingy. WidgetList, and only WidgetList, knows how to construct those ThingyParts, and it needs the current loop variable in order to construct.

Ultimately what needs to happen is that I need to Provide a different ThingyPart per loop iteration. Is there any way to achieve this without touching Widget?

Alternative question: I notice that I can receive the raw Injector in my WidgetList. Is there a way to dynamically add and remove the child injectors that my viewchildren see using the injector API? If there is, then I can create a new child injector in the loop and delete off the old one. (You know what would be cool? A "provide" template directive that does this for me.)

masonk
  • 9,176
  • 2
  • 47
  • 58
  • is `Thingy` an angular component? – shusson Mar 07 '17 at 01:18
  • No, it's an @Injectable. Just a service – masonk Mar 07 '17 at 01:54
  • I'd avoid DI on `Thingy` and just Instantiate it in `Widget`. This sounds like a composition vs dependency question http://stackoverflow.com/questions/21022012/difference-between-dependency-and-composition – shusson Mar 07 '17 at 03:16
  • There are umpteen ways to make this work if I touch `Widget`. But that rather defeats the point of DI, because it makes `Thingy` into `Widget`'s concern when it really isn't. I mean if DI can't do this, why the hell am I bothering? – masonk Mar 07 '17 at 03:18
  • Sure, but how is DI helping in this situation? – shusson Mar 07 '17 at 03:34
  • Well, at the moment, it's definitely not. In fact, I've already basically done what you've suggested: `@Input thingyPartOverride: ThingyPart` inside of `Widget`, and then construct a `Thing` inside of `Widget` if `thingyPartOverride` is set. But, I mean, wow. It just feels bad. – masonk Mar 07 '17 at 03:55

1 Answers1

1

It sounds like in the WidgetList component, you need to provide ThingyPart as a factory. Then, you can create instances of ThingyPart using data from WidgetList.

eg.

  @Component({
     selector: 'widget-list',
    .....
    providers: [
      { provide: ThingConfigService, useFactory: (widget ) => {
         ...  // use the Widget here to configure ThingConfigService as you need
              // then you can use ThingConfigService within your ThingyPart
              // and pull out the data that you need
         }, deps: [ Widget ]   
      }
    ]
 ......

That useFactory option accepts a function that can return your configured ThingyPart. It's hard to guide you further without understanding more of what you're trying to accomplish.

Thoughtram has an article about dependency injection that may prove useful.

snorkpete
  • 14,278
  • 3
  • 40
  • 57
  • How can I use the data from my WidgetList instance inside of the factory method? Factories were one of the first things I looked at, but that factory function has nothing useful: `this` is undefined, and I can't get it to inject anything except what's available in parent containers, let alone what I really need, which is the loop variable. – masonk Mar 07 '17 at 03:55
  • https://plnkr.co/edit/CxMPf3?p=info that plunker is trying to show what you can do with the useFactory option. Note that you have to provide a service that you then configure in the useFactory function with what you need (you can't 'provide' the component itself - i'll update my answer to reflect that) – snorkpete Mar 07 '17 at 12:02