Marcus Krahl
Marcus Krahl

Reputation: 684

parent injector not working correctly for nested ng-content

When using <ng-content></ng-content> for content projection, it is usually possible to access the parent component via dependency injection:

@Component({
  selector: 'app-parent',
  template: 'Parent / <ng-content></ng-content>'
})
export class ParentComponent {}

@Component({
  selector: 'app-child',
  template: 'Child / Has parent: {{parentComponent != null}}'
})
export class ChildComponent {
  constructor(@Optional() public parentComponent: ParentComponent) {}
}
<app-parent>
  <app-child></app-child>
</app-parent>

<!-- this will output Parent / Child / Has parent: true -->

However when adding another layer, this does not seem to work although app-parent is still the direct parent of app-child in the DOM:

@Component({
  selector: 'app-host',
  template: `Host / <app-parent><ng-content></ng-content></app-parent>`
})
<app-host>
  <app-child></app-child>
</app-host>

<!-- this will output: Host / Parent / Child / Has parent: false -->

See also this stackblitz for an example: https://stackblitz.com/edit/angular-ivy-e7c6i8?file=src/app/app.component.html

Is there some way to access ParentComponent from ChildComponent even in a nested scenario?

Upvotes: 1

Views: 1189

Answers (1)

TotallyNewb
TotallyNewb

Reputation: 4790

This will not work, because ChildComponent is being projected as content of the HostComponent. So in the eyes of the HierarchicalInjector ChildComponent and ParentComponent are siblings, since they are both children of the HostComponent.

You might be able to get around it by making your HostComponent a provider of the ParentComponent by using forwardRef and assigning the value in proper lifecycle hook, but if that works it still would be sketchy to say the least, since the actual value of the reference would be null during injection in dependent components.

Basically, trying to access parent component directly is a bad practice and you should try to avoid that. Instead use @Input / @Output for communication between Child - Parent. If there's a lots of logic going on, you can instead create a separate service (which could be either singleton, i.e. provided on the application level, or be provided by other component, e.g. ParentComponent, and hence be scoped to one Parent-Child pair.).

Upvotes: 2

Related Questions