如何动态地将组件作为子组件添加到指令中?

Posted

技术标签:

【中文标题】如何动态地将组件作为子组件添加到指令中?【英文标题】:How to dynamically add a component as a child to a directive? 【发布时间】:2016-12-16 02:33:30 【问题描述】:

我一直在试验 Angular 2,我已经能够通过获取现有子级的 @ViewChild 然后使用 ComponentResolver 添加我的动态组件来动态地将一个组件添加到另一个子级。

但是,如果您无法控制模板(即您正在动态地将组件添加到指令的子级),您应该怎么做?我不知道我的指令将在容器中包含哪些元素,那么我如何获得类似的 ViewContainerRef 呢?

编辑: 我似乎在获取指令的 @ViewChild 时也遇到了问题。 Here's 我在我的应用程序中发生的事情..

Hello.component.ts

import  Component  from '@angular/core'

@Component(
  selector: 'hello',
  template: '<h1>Hi!</h1>',
  styles: ['h1background-color: green']
)
export class HelloComponent 

Test.directive.ts

import  Directive, ViewChild, ViewContainerRef, ComponentResolver, OnInit  from '@angular/core';
import  HelloComponent  from './hello.component'

@Directive(
  selector: '[testDir]'
)
export class TestDirective implements OnInit 
  @ViewChild('div', read: ViewContainerRef) div;

  constructor(private viewContainerRef: ViewContainerRef, private componentResolver: ComponentResolver) 

  ngOnInit() 
    this.componentResolver.resolveComponent(HelloComponent).then((factory) => 
      this.div.createComponent(factory);
      this.viewContainerRef.createComponent(factory);
    );
  

app.component.ts

import  Component  from '@angular/core';
import  TestDirective  from './app.directive';
import  HelloComponent  from './hello.component'

@Component(
  selector: 'my-app',
  template: `
    <div testDir>
      <div #div></div>
    </div>
  `,
  directives: [TestDirective, HelloComponent]
)
export class AppComponent  

【问题讨论】:

【参考方案1】:

您可以使用Renderer2 服务将组件添加到指令的子级。

此示例使用新创建的组件的元素引用,并通过渲染服务将其附加到当前元素引用。

下面是一个在点击它时执行的指令,你也可以在 onInit 上执行相同的操作:

@Directive(
  selector: '[mydirective]'
)
export class MyDirective 
  constructor(
    private cfResolver: ComponentFactoryResolver,
    public vcRef: ViewContainerRef,
    public elementRef: ElementRef,
    private renderer: Renderer2
  )  


  @HostListener('click', ['$event'])
  onClick() 
    const factory =
      this.cfResolver.resolveComponentFactory(HelloComponent);
    const componentRef = this.vcRef.createComponent(factory);
    this.renderer.appendChild(
      this.vcRef.element.nativeElement,
      componentRef.injector.get(HelloComponent).elementRef.nativeElement
    );
  

您还可以在将 Dynamic 组件附加到当前宿主元素之前设置其任何 Input 属性。

【讨论】:

elementRef 不存在,必须作为公共添加到 HelloComponent 的构造函数中:constructor(public elementRef: ElementRef) 附加“componentRef.instance.elementRef.nativeElement”而不是“componentRef.injector.get(HelloComponent).elementRef.nativeElement”有什么区别吗?我发现两者都可以工作 如果 renderer.appendChild 没有完成,组件将被附加到应用指令的父节点(参见github.com/angular/angular/issues/30743)

以上是关于如何动态地将组件作为子组件添加到指令中?的主要内容,如果未能解决你的问题,请参考以下文章

Angular 表单:如何动态添加/删除子表单组件

如何使用 React 中的 CSS 模块将多个类动态传递给子组件

如何根据另一个组件的存在有条件地将类添加到 Magnolia 组件模板?

vue中父组件如何动态修改子组件的值?

如何动态地将数组添加到 react-bootstrap 表中?

如何正确地将资源 (*.res) 文件添加到带有组件的包中?