将父级的模板内容注入子级

SBK*_*per 6 angular

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

  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');
 }
Run Code Online (Sandbox Code Playgroud)

标记就像这样:

<div #containerDiv>
  <child-component *myStructuralDirective>
  </child-component>
</div>
Run Code Online (Sandbox Code Playgroud)

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

<div #containerDiv>
  <child-component *myStructuralDirective>
  </child-component>
</div>
<ng-template #footer>
   <p>Some other markup</p>
</ng-template>
Run Code Online (Sandbox Code Playgroud)

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

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

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

KSh*_*ger 9

是的,您可以使用以下方法将 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>
Run Code Online (Sandbox Code Playgroud)

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);
  }
Run Code Online (Sandbox Code Playgroud)

}

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>
Run Code Online (Sandbox Code Playgroud)

4.) 或者你可以在你的ChildComponent上提供一个容器

a.) ChildComponent 示例模板

<p>Header</p> 
<p>Content</p>

<div #container></div>
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

}

您的 ng-template 现在将出现在您想要的位置。