在我的情况下,如果某个组件位于特定组件内部,则其行为应有所不同。因此,我想浏览一下父母,以找到正确类型的组件,该组件通过简单情况下的依赖注入可以很好地工作:
子组件
@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);
}
}
父组件
@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;
}
用法,有效
<spike-parent [id]="1">
<spike-child></spike-child>
</spike-parent>
不幸的是,如果像这样通过内容投影添加一个间接访问,则此操作将不再起作用:
ProjectedContent组件
@Component({
selector: 'spike-projected-content',
template: '<spike-parent [id]="2"><ng-content></ng-content></spike-parent>'
})
export class ProjectedContentComponent { }
用法,不起作用
<spike-projected-content>
<spike-child></spike-child>
</spike-projected-content>
很明显,在运行时,子级将再次位于父级中,但是现在它总是作为注入的参数为null。我了解所计划的内容将保留原始上下文(包括注入器链),这几乎总是有用的,但是有什么方法可以解决这种情况?我阅读了有关ngComponentOutlet的信息,它看起来可能会有所帮助,但我没有完全看到它的适用范围。我也没有发现任何问题可以解决这种情况。我想我可以查询DOM以获得结果,但是我显然想避免这种情况,并为此使用Angular机制。
非常感谢您!
答案 0 :(得分:2)
我只能看到两种方式(DOM黑客除外):
viewContainerRef.createEmbeddedView
中覆盖注入器,但是可以传递上下文信息(例如context-parameter-in-angular或使用NgTemplateOutlet
)。{provide: Token, useExisting: forwardRef(() => Child)}
提供自身,它允许使用@ContentChildren(Token)
并获取所有投影子组件的列表,并调用任何方法/设置器。 答案 1 :(得分:1)
从组件的角度来看,ChildComponent
是ParentComponent
的兄弟姐妹,他们没有父子关系。都是具有共享父级ProjectedContentComponent
在DOM中,它们的HTMLElement表示形式是父/子顺序,但这与组件结构是分开的。我们可以detatch()任何组件的HTML并将其放置在DOM中的任何位置-这就是ng-content
所做的
使用共享的父级(ProjectedContentComponent)在同级之间传递引用: StackBlitz Demo
组件结构展示了共享的父级而不是父子关系 StackBlitz Demo
答案 2 :(得分:0)
为了解决眼前的难题,我现在开始查询DOM。这感觉确实很棘手,我将不胜感激其他建议,但我也想与任何有类似案件的人分享我的解决方案。
注意::如果我的组件位于其他组件内部,则我的解决方案只会发现 。它没有引用该组件的实例,因为在我的情况下我不需要它。
提供以下功能:
private hasParent(element: ElementRef, selector: string): boolean {
let parent = element.nativeElement;
while(parent = parent.parentElement) {
if (parent.matches(selector)) { return true; }
}
return false;
}
我们可以找出我们的组件是否在这样的特定其他组件内:
public constructor(element: ElementRef) {
const isChildOfSpikeParent = this.hasParent(element, 'spike-parent');
我还尝试了以下方法来消除硬编码的选择器,但是它不适用于AOT,因此我放弃了该方法:
function getSelectorOfComponent(componentType: Function): string {
// Reading annotations, see: https://stackoverflow.com/questions/46937746/how-to-retrieve-a-components-metadata-in-angular
const decorators: any[] = (<any>componentType).__annotations__;
const componentDecorator = decorators && decorators.find(d => d.ngMetadataName === 'Component');
return componentDecorator && componentDecorator.selector;
}