【问题标题】:Injecting template content from parent into child将模板内容从父级注入子级
【发布时间】:2019-03-07 01:38:30
【问题描述】:

我有一个第 3 方库组件,我试图通过在某个点添加一些额外的标记来自定义它。我正在使用结构指令来执行此操作,目前我正在使用渲染器以编程方式添加和样式化节点,如下所示:

  const headerDiv = this.newDiv();
   el = this.nativeElement.querySelector('div.ui-dropdown-items-wrapper');
   this.renderer.appendChild(el, this.renderer.createText('sometext'));


  private newDiv(): Element {
   return this.renderer.createElement('div');
 }

标记是这样的:

<div #containerDiv>
  <child-component *myStructuralDirective>
  </child-component>
</div>

有没有办法直接在父组件的标记中定义&lt;ng-template&gt; 并使用渲染器在某个点注入它?像这样的:

<div #containerDiv>
  <child-component *myStructuralDirective>
  </child-component>
</div>
<ng-template #footer>
   <p>Some other markup</p>
</ng-template>

然后在我选择的某个点将#footer 的内容注入到子组件中。注意 - 我无法访问孩子,因为它是已编译的第 3 方库。

我想看看是否有更好的方法将标记定义为模板变量,我可以在我的结构指令中使用,访问该模板并在某个点将其注入子组件。

编辑 - 我正在查看ViewContainerRef.insert,不幸的是,这只能根据其他ViewRefs 的位置插入模板。由于我无法更改第 3 方组件的标记,我可以定义一个 ng-container 来标记插入点,并且只需要使用 CSS 选择器。不确定是否有办法根据元素位置插入模板。我知道这是 2 个离散的概念(Angular View 抽象与直接 DOM 插入),所以我不乐观这可以做到!

【问题讨论】:

    标签: angular


    【解决方案1】:

    是的,您可以使用以下方法将 ng-template 注入到您希望放置的任何位置:

    1.) 使用 ng-container

     <div #containerDiv>
      <child-component *myStructuralDirective></child-component>
    
      // This will show your template
      <ng-container [ngTemplateOutlet]="footer"></ng-container>  
    
    </div>
    
    <ng-template #footer>
       <p>Some other markup</p>
    </ng-template>
    

    2.) 或者使用带有 ViewContainerRef 和 CreateEmbeddedView 的 结构指令 注入它

    a.)Supply the footer template on your childComponent. myStructuralDirective
    is now both a directive and an [] input that asks for a value.
    
    <child-component [myStructuralDirective]="footer"></child-component>
    
    b.) Use default ViewContainerRef declared on the constructor which pertains 
    to your current view/screen which the template the template is attached example for this - it is attached on ChildComponentView
    
    @Directive({
        selector: 'myStructuralDirective'
    })
    export class MyStructuralDirective implements AfterViewInit {
    
     @Input() myStructuralDirective: TemplateRef<any>;
    
     constructor(private container: ViewContainerRef) {}
    
     ngAfterViewInit() {
         this.container.createEmbeddedView(this.myStructuralDirective);
      }
    

    }

    3.) 或者在 ChildComponent 上提供一个 @Input() 并传递页脚模板值

     a.)  <child-component *myStructuralDirective
                           [footerTemplate]="footer"></child-component>
    
     b.) On the ChildComponent Class, declare its @Input() property
    
     @Component({
         selector: 'child-component'
      })
      export class ChildComponent {
    
        @Input() footerTemplate: TemplateRef<any>;
    
      }
    
     c.) On your ChildComponent Template, supply an ng-container to wherever you want it to be placed.
    
     <h1>Header</h1>
     <h1>Content</h1>
    
     <ng-container [ngTemplateOutlet]="footerTemplate"></ng-container>
    

    4.) 或者您可以在 ChildComponent

    上提供一个容器

    a.) ChildComponent 示例模板

    <p>Header</p> 
    <p>Content</p>
    
    <div #container></div>
    

    b.) 使用 @Input() 在 ChildComponent 类上声明 ViewContainerRef 和 TemplateRef,这需要来自组件的页脚模板值

    @Component({...})
    export class ChildComponent implements AfterViewInit {
    
      //From your template <div #container></div> 
      @ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef;
    
      @Input() footerTemplate: TemplateRef<any>;
    
    
      ngAfterViewInit() {
         this.container.createEmbeddedView(this.footerTemplate);
    }
    

    }

    您的 ng 模板现在将出现在您想要的位置。

    【讨论】:

    • 谢谢,但这不是我想要的。我无法修改子项中的任何标记,我必须将模板插入到子项 inside 的任意点,仅使用 css 选择器来选择插入点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-26
    • 1970-01-01
    • 2021-03-15
    • 2016-07-06
    • 2022-08-09
    相关资源
    最近更新 更多