2017-01-31 71 views
4

我的目標是創建一個子組件並插入到父組件模板中。有些例子可以做到這一點。 但是,我在父組件中動態創建父組件模板(DOM元素),而大多數靜態顯示的示例使用捕獲元素創建模板。Angular 2:創建組件時動態插入捕獲元素(動態)

下面的代碼

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> 

而不是在#captureElement在子組件將被插入靜態定義,我想在父組件中動態創建它並使其成爲子組件。

這裏有一個問題清單我提到之前,我問過這個問題

試過幾件事情

  1. 嘗試以編程方式創建div元素,#captureElement作爲 屬性,但這不起作用。
  2. 試圖以編程方式創建隨機元素並使用ViewContainerRef來查找它。那也行不通。

回答

10

我們無法創建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)之後,通過cal登記其changeDetectorcomponentRef.hostView延伸ChangeDetectorRef)凌上面提到appRef.attachView(否則更改檢測將不會爲您的組件工作)

4),最後你的附加組件的根節點到主機元素

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

Plunker Example

參見

+0

非常感謝!這個HtmlContainer類將坐在哪裏?我的意思是......哪個組件? – am3

+0

我創建了'HtmlContainer'作爲輔助類,它工作得很漂亮。再次感謝。你能否詳細說明HtmlContainer類正在做什麼? – am3

+0

謝謝。如何維護動態組件以便我可以刪除它們?每次創建一個新的動態組件時,都嘗試在'addComponent'中保存一個對'componentRef.instance'的引用存儲的對象。在這個上調用'.destroy()'確實沒問題。有一個更好的方法嗎? – am3