【问题标题】: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: ['h1{background-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 { 
}

【问题讨论】:

    标签: angular


    【解决方案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
    猜你喜欢
    • 2017-07-24
    • 1970-01-01
    • 1970-01-01
    • 2013-03-23
    • 2023-04-05
    • 2018-07-03
    • 1970-01-01
    • 2021-06-15
    • 1970-01-01
    相关资源
    最近更新 更多