In my situation, I have a component that should behave differently if it is inside a specific component. So I want to look through the parents to find the component of the correct type, which works well through dependency injection in the simple case:
Child Component
@Component({
selector: 'spike-child',
template: `<div>I am the child, trying to find my parent.
<button (click)="log()">Test</button></div>`
})
export class ChildComponent {
// Get Parent through dependency injection; or null if not present.
public constructor(@Optional() private parent: ParentComponent) { }
public log(): void {
console.log('Parent', this.parent);
console.log('Parent.Id', this.parent && this.parent.id);
}
}
Parent Component
@Component({
selector: 'spike-parent',
template: `
<div>
<div>I am the parent of the content below, ID = {{ id }}:</div>
<ng-content></ng-content>
</div>`
})
export class ParentComponent {
@Input()
public id: number;
}
Usage, works
<spike-parent [id]="1">
<spike-child></spike-child>
</spike-parent>
Unfortunately, this does not work anymore if we add one more indirection through content projection like this:
ProjectedContent Component
@Component({
selector: 'spike-projected-content',
template: '<spike-parent [id]="2"><ng-content></ng-content></spike-parent>'
})
export class ProjectedContentComponent { }
Usage, does not work
<spike-projected-content>
<spike-child></spike-child>
</spike-projected-content>
Obviously, the child will again be inside a parent at runtime, but now it always gets null as the injected parameter. I understand that content that is projected keeps the original context (including the injector chain), which is definitely almost always helpful, but is there some way to tackle this situation? I read about ngComponentOutlet which looks like it might help, but I didn't exactly see how it could fit. I also didn't find any questions that take this last step from this situation. I guess I could query the DOM to achieve the result, but I obviously would like to avoid that and use Angular mechanics for this.
Thank you so much!
@Input() and @Output() give a child component a way to communicate with its parent component. @Input() lets a parent component update data in the child component. Conversely, @Output() lets the child send data to a parent component.
Otherwise, remember the three steps: Prepare Child component to emit data. Bind Property in Parent Component template. Use Property in Parent Component class.
@Input Decorator: This is used to define an input property and it is used to send data from parent component to child component.
I can only see two ways (except DOM hacking):
viewContainerRef.createEmbeddedView
, however there is option to pass context information (example context-parameter-in-angular, or use NgTemplateOutlet
).{provide: Token, useExisting: forwardRef(() => Child)}
, it allows to use @ContentChildren(Token)
and get list of all projected children, and call any method/setter. If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With