Angular 2: dynamically nesting a capture element when creating components (dynamically)

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

Here is the code

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

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

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

Here is a list of questions that I asked before I asked this question

  • div #captureElement , .
  • ViewContainerRef . .
+4
1

ViewContainerRef, ViewContainerRef .

2.3.0 attachView, ApplicationRef. , , :

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)

this.componentFactoryResolver.resolveComponentFactory(component);

2) , compFactory.create

3) changeDetector (componentRef.hostView extends ChangeDetectorRef), appRef.attachView ( )

4) , , rootNode

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

:

@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());
  }
}

.

+10

Source: https://habr.com/ru/post/1668345/


All Articles