Pass service/provider for specific child component to use as inject value

Issue

FormService contains state for parts of form.

export class ArrayComponent implements OnInit {

   formServices: FormService[] = [];

   constructor(
        @Inject(FormService) public parentFormService: FormService,
    ) {
    }

   ngOnInit(): void {
      // Here I create lets say 10 FormService objects, that have to go to there separated child components.
      this.parentFormService.data$.subscribe((d: any[]) => d.foreach((v: any) => this.formServices.push(new FormService(v))))
   }
}

Lets imagine that based on some data, I create new FormService. I need to be able to pass this created FormService for a specific child component.

<ng-container *ngFor="let s of formServices">
   <array-item [inject/providers]="s"></array-item>
</ng-container>

Is there a way to pass this injectable service into a component as a Injectable?

You may be asking why would I need it to be injectable or why cant I just pass it in as @Input. The issue is that down in the tree of components there is for example a TextInputComponent that is trying to Inject a FormService to store state and do other Input things.

I pretty much want to do what @Component({providers: []}) does, but outside of the component, so I can directly control the provided Service and have access to it from Parent and Child component.

EDIT:
// More precise thing i want to do simplified

<array-item [inject/providers]="formServices[0]"></array-item>
<array-item [inject/providers]="formServices[1]"></array-item>
<array-item [inject/providers]="formServices[2]"></array-item>
<array-item [inject/providers]="formServices[3]"></array-item>

and then down the line inside of array-item component there is a component that uses @Inject to inject FormService and use it.

Solution

This is very possible.

For every child its possible to create an Injector like this –

...

constructor(
        ...
        private injector: Injector,
        ...
    ) {
    }
...

Injector.create({providers: [...providder here...], parent: this.injector})

And then pass it to a component that renders further children like this –

...
@Input() injector!: Injector;
...
    constructor(
        ...
        public viewContainerRef: ViewContainerRef,
        ...
    ) {

    }
...
ngOnInit(): void {
        ...
        const component = this.viewContainerRef.createComponent(...Component..., {
            ...
            injector: this.injector
            ...
            }),
        });
        ... // Set @Input attributes here with component.instance.
        component.changeDetectorRef.detectChanges();
        ...
    }

Answered By – DaveLV2

Answer Checked By – Mildred Charles (AngularFixing Admin)

Leave a Reply

Your email address will not be published.