我有一个外部组件(蓝绿色),其中包含一些我自己的 flexbox 工具栏ui-button
纽扣。和一个内部组件,主要在棕色区域做它的事情(如你所料)。
但是,根据内部组件(有几个来回切换的组件),必须在该顶部/底部栏中插入更多上下文按钮。
(在外部使用绝对定位的 CSS 技巧不是一种选择,根据大小和便利性,外部工具栏的位置、大小等可能会有很大差异......)
现在我的问题是:
我可以以某种方式传递对某些占位符(黑色方括号)的引用(就像常规 content projection/transclusion 一样),并用来自子组件的内容填充它们吗?
像 ngTemplate[Outlet] 这样的东西也许?和/或 using @Output ?
我想“向上传递”超过plain text
或 simple <b>rich</b> <i>html</i>
但理想情况下是真正的 Angular 模板代码,包括自定义组件,如
<ui-button icon="up.svg" (click)='...'></ui-button>
<ui-button icon="down.svg" (click)='...'></ui-button>
...在外部组件的顶部栏中引导到:
<section class='some-flexbox'>
<ui-button icon="home.svg" (click)='...'></ui-button>
<ui-button icon="up.svg" (click)='...'></ui-button>
<ui-button icon="down.svg" (click)='...'></ui-button>
<ui-button icon="help.svg" (click)='...'></ui-button>
<ui-button icon="account.svg" (click)='...'></ui-button>
</section>
想一想,那些添加的按钮的点击事件应该会回到 child 身上,叹息......
更新
ngTemplateOutlet
听起来很有趣We can also take the template itself and instantiate it anywhere on the page, using the ngTemplateOutlet directive:
正在检查,仍然不确定如何...
最佳答案
有两种可能的方法可以实现所需的行为。
以下是这两种解决方案的快速说明。
1. 使用 PortalModule Demo Link
您可以在子组件的模板文件中定义模板。
<ng-template #templateForParent>
<button (click)="onTemplateBtnClicked('btn from child')">
Button from Child
</button>
</ng-template>
然后使用
@viewChid
在您的子组件文件中获取该模板的引用装饰师。@ViewChild("templateForParent", { static: true }) templateForParent: TemplateRef<any>;
那么你可以创建一个
TemplatePortal
使用该模板 ref 并随时将该门户传递给父级。ngAfterViewInit(): void {
const templatePortal = new TemplatePortal(this.templateForParent, this.viewContainerRef);
setTimeout(() => {
this.renderToParent.emit(templatePortal);
});
}
而父组件的模板文件可能是这样的。
<div fxLayout="row" fxLayoutAlign="space-between center">
<button (click)="onBtnClick('one')">one</button>
<button (click)="onBtnClick('two')">two</button>
<ng-container [cdkPortalOutlet]="selectedPortal"></ng-container> <!-- pass the portal to the portalOutlet -->
<app-button-group (renderToParent)="selectedPortal = $event"></app-button-group>
<button (click)="onBtnClick('five')">five</button>
</div>
就是这样。现在您已经为父组件渲染了一个模板,并且该组件仍然具有
click
的绑定(bind)。事件。并且 click 事件处理程序是在子组件内部定义的。您可以使用相同的方式 ComponentPortal或 DomPortal
2. 使用自定义指令 Demo Link
您可以按如下方式创建一个 Angular Directive(指令),它将元素从其宿主组件移动到宿主组件的父组件。
import {Directive,TemplateRef,ElementRef,OnChanges,SimpleChanges,OnInit,Renderer2,DoCheck} from "@angular/core";
@Directive({
selector: "[appRenderToParent]"
})
export class RenderToParentDirective implements OnInit {
constructor(private elementRef: ElementRef<HTMLElement>) {}
ngOnInit(): void {
const childNodes = [];
this.elementRef.nativeElement.childNodes.forEach(node =>
childNodes.push(node)
);
childNodes.forEach(node => {
this.elementRef.nativeElement.parentElement.insertBefore(
node,
this.elementRef.nativeElement
);
});
this.elementRef.nativeElement.style.display = "none";
}
}
然后你可以在任何组件上使用这个指令。
<div fxLayout="row" fxLayoutAlign="space-between center">
<button (click)="onBtnClick('one')">one</button>
<button (click)="onBtnClick('two')">two</button>
<app-button-group appRenderToParent></app-button-group>
<button (click)="onBtnClick('five')">five</button>
</div>
这里
<app-button-group>
有以下模板文件。<button (click)="onBtnClick('three')">three</button>
<button (click)="onBtnClick('four')">four</button>
所以我们的指令会将按钮元素移动到其宿主的父组件。我们只是在 DOM 树中移动 DOM 节点,因此与这些元素绑定(bind)的所有事件仍然有效。
我们可以修改指令以接受类名或 id,并仅移动具有该类名或 id 的元素。
我希望这将有所帮助。我建议阅读文档以获取有关 PortalModule 的更多信息。
关于Angular 2 嵌入 : Can I pass slot content upward to a parent Component,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60418793/