Angular 2 嵌入 : Can I pass slot content upward to a parent Component

标签 angular transclusion

我有一个外部组件(蓝绿色),其中包含一些我自己的 flexbox 工具栏ui-button纽扣。和一个内部组件,主要在棕色区域做它的事情(如你所料)。



但是,根据内部组件(有几个来回切换的组件),必须在该顶部/底部栏中插入更多上下文按钮。

(在外部使用绝对定位的 CSS 技巧不是一种选择,根据大小和便利性,外部工具栏的位置、大小等可能会有很大差异......)

现在我的问题是:

我可以以某种方式传递对某些占位符(黑色方括号)的引用(就像常规 content projection/transclusion 一样),并用来自子组件的内容填充它们吗?

ngTemplate[Outlet] 这样的东西也许?和/或 using @Output ?

我想“向上传递”超过plain textsimple <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:



正在检查,仍然不确定如何...

最佳答案

有两种可能的方法可以实现所需的行为。

  • 使用 Angular CDK 的 PortalModule
  • 通过创建使用 javascript dom apis 将元素从子组件移动到父组件的自定义指令。

  • 以下是这两种解决方案的快速说明。

    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 事件处理程序是在子组件内部定义的。

    您可以使用相同的方式 ComponentPortalDomPortal

    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/

    相关文章:

    angularjs - Angular : difference when using template or templateUrl

    typescript - Angular2 中的动态模板 "transclusion"

    angular - 获取所有当前(事件)订阅

    angular - 通过 @ViewChild 访问组件的 nativeElement

    javascript - Angular 2 组合表单验证

    angular - 是否可以使用单个 angular-cli 命令生成多个 Angular 组件,例如 ng generate component comp1, comp2, comp3?

    angular - 将值传递给子组件 Angular 7

    javascript - 获取 Angular Directive(指令)中的原始嵌入内容

    Angular 2 - 如何与嵌入模板共享组件数据

    javascript - ng-transclude 在模板 AngularJS 中不起作用