本文介绍了角度2:在动态创建组件时动态插入捕获元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的目标是创建一个子组件并将其插入父组件模板.有一些例子可以做到这一点. 但是,我在父组件中动态创建了父组件模板(DOM元素),而所示的大多数示例都使用capture元素静态创建了模板.

My goal is to create a child component and insert into the parent component template. There are examples to do this. However, I create parent component template (DOM Elements) dynamically in the parent component while most of the examples shown statically create the template with the capture element.

这是代码

app.component

app.component

import {Component, ViewChild, ViewContainerRef, ComponentFactoryResolver} from '@angular/core';
import {NewChildComponent} from "./newChild.component";

@Component({
 selector: 'app-main',
 templateUrl: 'app.component.html'
})
export class AppComponent {

 @ViewChild('captureElement', {read: ViewContainerRef})
 captureElement: ViewContainerRef;

 constructor (private componentFactoryResolver: ComponentFactoryResolver) {
 var childComponent = this.componentFactoryResolver.resolveComponentFactory(NewChildComponent);

 var myArea = document.getElementById('myArea');
 var myRow = document.createElement("div");
 myArea.appendChild(myRow);

 //I want to add the capture element #myCapture as a child of myRow
 //Add something like this <div #captureElement></div> programmatically through JS/TS
 // How can I do this?

 // I then create the component
  this.parent.createComponent(NewChildComponent);

 }

app.component.html

app.component.html

<div id="myArea">
  <!-- Static way of doing it -->
  <!--<div #captureElement></div>-->
</div>

我不想在#captureElement中静态定义子组件的插入位置,而是想在父组件中动态创建它,并使它成为子组件.

Instead of statically defining in #captureElement where the child component would be inserted, I would like to create it dynamically in the parent component and make it a child component.

以下是我问这个问题之前我提到的问题列表

Here are a list of questions I referred before I asked this question

  • Angular2: Insert a dynamic component as child of a container in the DOM
  • How to place a dynamic component in a container
  • Angular 2 dynamic tabs with user-click chosen components

尝试了几件事

  1. 试图创建一个以#captureElement作为元素的div元素以编程方式分配属性,但这不起作用.
  2. 试图以编程方式创建随机元素,然后使用ViewContainerRef进行查找.那也不行.
  1. Tried to create a div element with a #captureElement as anattribute programmatically but that doesn't work.
  2. Tried to create a random element programmatically and use ViewContainerRef to find it. That doesn't work either.

推荐答案

我们无法创建ViewContainerRef,因为ViewContainerRef仅存在于视图中.

We can't create a ViewContainerRef, as a ViewContainerRef only exists within a view.

在2.3.0中,引入了attachView,它使您能够将更改检测附加到ApplicationRef.您可以创建一些类来封装您的逻辑,例如:

In 2.3.0, attachView was introduced which allows you to be able to attach change detection to the ApplicationRef. You can create some class that will encapsulate your logic like:

export class HtmlContainer {
   private attached: boolean = false;

   private disposeFn: () => void;

   constructor(
    private hostElement: Element,
    private appRef: ApplicationRef,
    private componentFactoryResolver: ComponentFactoryResolver,
    private injector: Injector) {
  }

  attach(component: Type<any>) : ComponentRef<any> {
    if(this.attached) {
      throw new Error('component has already been attached')
    }

    this.attached = true;
    const childComponentFactory = this.componentFactoryResolver.resolveComponentFactory(component);

    let componentRef = childComponentFactory.create(this.injector);

    this.appRef.attachView(componentRef.hostView);
    this.disposeFn = () => {
        this.appRef.detachView(componentRef.hostView);
        componentRef.destroy();
    };

    this.hostElement.appendChild((componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0]);

    return componentRef;
  }

  dispose() {
    if(this.attached) {
      this.disposeFn();
    }
  }
}

此类仅是

1)解决您的动态组件

1) resolves your dynamic component

this.componentFactoryResolver.resolveComponentFactory(component);

2)然后通过调用compFactory.create

3)之后,通过调用上述appRef.attachView来注册其changeDetector(componentRef.hostView扩展ChangeDetectorRef)(否则,更改检测不适用于您的组件)

3) after that registers its changeDetector (componentRef.hostView extends ChangeDetectorRef) by calling mentioned above appRef.attachView (otherwise change detection won't work for your component)

4),最后将组件的rootNode附加到主机元素

4) and finally appends the rootNode of your component to the host element

this.hostElement.appendChild((componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0]);

您可以按以下方式使用它:

You can use it as follows:

@Component({
  selector: 'my-app',
  template: `<div id="myArea"></div> `,
  entryComponents: [NewChildComponent]
})
export class AppComponent {
  containers: HtmlContainer[] = [];

  constructor(
    private appRef: ApplicationRef,
    private componentFactoryResolver: ComponentFactoryResolver,
    private injector: Injector) {
  }

  ngOnInit() {
    var myArea = document.getElementById('myArea');
    var myRow = document.createElement("div");
    myArea.appendChild(myRow);

    this.addComponentToRow(NewChildComponent, myRow, 'test1');
    this.addComponentToRow(NewChildComponent, myRow, 'test2');
  }

  addComponentToRow(component: Type<any>, row: HTMLElement, param: string) {
    let container = new HtmlContainer(row, this.appRef, this.componentFactoryResolver, this.injector);
    let componentRef = container.attach(component);
    componentRef.instance.param1 = param;

    this.containers.push(container);
  }

  ngOnDestroy() {
    this.containers.forEach(container => container.dispose());
  }
}

柱塞示例

Plunker Example

另请参见

  • Angular2 - Component into dynamicaly created element
  • Angular2 Dynamic Component Injection in Root
  • https://github.com/angular/material2/blob/2.0.0-beta.1/src/lib/core/portal/dom-portal-host.ts#L30-L86 (you can find here fallback for angular < 2.3.0)

这篇关于角度2:在动态创建组件时动态插入捕获元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 17:53