2016-09-25 14 views
8

Poszukuję sposobu na utworzenie instancji składnika w Angular2 z kodu innego komponentu. W przeciwieństwie do wielu osób, które zadały podobne pytanie, nie interesuje mnie dynamiczne kompilowanie nowego komponentu, tylko tworzenie i wstawianie takiego, który już istnieje w mojej aplikacji.Angular 2.0 final: jak utworzyć instancję komponentu z kodu

Na przykład:

powiedzieć, że mają dwa składniki:

desce rozdzielczej item.component.ts

import { Component } from "@angular/core"; 

@Component({ 
    selector: "dashboard-item", 
    template: "Some dashboard item with functionality" 
}) 
export class DashboardItemComponent { 
    constructor() {} 

    onInit() {} 
} 

dashboard.component.ts

import { Component } from "@angular/core"; 

@Component({ 
    selector: "dashboard", 
    template: "<h1>Dashboard!</h1><div #placeholder></div>" 
}) 
export class DashboardComponent { 
    constructor() {} 

    onInit() {} 
} 

Czego szukam, to sposób na utworzenie komponentu DashboardItemComponent w elemencie onInit składnika DashboardComponent i dodanie go do elementu div #placeholder.

Dwie rzeczy do uwaga:

Tych dwóch wcześniejszych emisji zadać podobne pytanie, ale ich odpowiedzi są albo raczej nijaka lub odnoszą się do wcześniejszej (beta) wersji Angular2 i wydają się nie działać.

+0

Można przyjrzeć się pierwsza opcja z http://stackoverflow.com/questions/39678963/load-existing-components-dynamically-angular-2-final-release/39680765#39680765 – yurzui

Odpowiedz

11

Oto demo pracy: https://plnkr.co/edit/pgkgYEwSwft3bLEW95Ta?p=preview

import {Component, NgModule, ViewChild, ElementRef, Input, Output, EventEmitter, ViewContainerRef, ComponentRef, ComponentFactoryResolver, ReflectiveInjector} from '@angular/core' 
import {BrowserModule} from '@angular/platform-browser' 

@Component({ 
    selector: 'any-comp', 
    template: '<div (click)="clicked.emit($event)">here i am.. {{name}}</div>' 
}) 
export class AnyComponent { 

    @Input() name; 
    @Output() clicked = new EventEmitter(); 

    constructor() { 
    console.log('some1 created me.. ! :)'); 
    } 
} 

@Component({ 
    selector: 'my-app', 
    template: ` 
    <div> 
     <h2>Hello {{name}}</h2> 
     <template #placeHolder> 
     </template> 
    </div> 
    `, 
}) 
export class App { 

    @ViewChild('placeHolder', {read: ViewContainerRef}) private _placeHolder: ElementRef; 

    name:string; 
    constructor(private _cmpFctryRslvr: ComponentFactoryResolver) { 
    this.name = 'Angular2' 
    } 

    ngOnInit() { 
    let cmp = this.createComponent(this._placeHolder, AnyComponent); 

    // set inputs.. 
    cmp.instance.name = 'peter'; 

    // set outputs.. 
    cmp.instance.clicked.subscribe(event => console.log(`clicked: ${event}`)); 

    // all inputs/outputs set? add it to the DOM .. 
    this._placeHolder.insert(cmp.hostView); 
    } 

    public createComponent (vCref: ViewContainerRef, type: any): ComponentRef { 

    let factory = this._cmpFctryRslvr.resolveComponentFactory(type); 

    // vCref is needed cause of that injector.. 
    let injector = ReflectiveInjector.fromResolvedProviders([], vCref.parentInjector); 

    // create component without adding it directly to the DOM 
    let comp = factory.create(injector); 

    return comp; 
    } 
} 

@NgModule({ 
    imports: [ BrowserModule ], 
    declarations: [ App, AnyComponent ], // ! IMPORTANT 
    entryComponents: [ AnyComponent ], // ! IMPORTANT --> would be lost due to Treeshaking.. 
    bootstrap: [ App ] 
}) 
export class AppModule {} 
+0

Dzięki za wejście, to na pewno pomaga. Wspomniałeś, że entryComponents jest ważny z powodu drzeworytu. Chociaż tak naprawdę nie wiem, co to oznacza, bez niego to nie działa. Czy ten proces robienia drzew zawsze jest wykonywany, gdy Angular wykonuje swoją kompilację? – Robba

+0

wydaje się, tak. nigdy nie jest tworzony w dowolnym miejscu, więc można go zoptymalizować i usunąć. – mxii

1

można umieścić składnik podrzędny wewnątrz elementu nadrzędnego.

<parent-component> 
    <child-component></child-component> 
</parent-component> 

Komponent potomny udostępnia właściwość EventEmitter, z której emituje zdarzenia, gdy coś się dzieje. Obiekt macierzysty wiąże się z tą właściwością zdarzenia i reaguje na te zdarzenia. https://angular.io/docs/ts/latest/cookbook/component-communication.html

0

Wydaje się, że (nowy?), Funkcja API do robienia tego, co zostało opisane w odpowiedzi mxii męska. ViewContainerRef ma metodę createComponent. Tworzy instancję komponentu i dodaje go do widoku.

let factory = this._cmpFctryRslvr.resolveComponentFactory(AnyComponent); 
let cmp = this.viewContainer.createComponent(factory); 
cmp.instance.name = 'peter'; 
Powiązane problemy