2016-06-16 3 views
4

Ich versuche, in Angular 2 ein ComponentContainer zu implementieren, so dass Sie dynamisch andere Komponenten hinzufügen können, ähnlich wie beispielsweise ein LinearLayout in Android.Angular 2 dynamisch Komponenteninstanz in Container

Bisher Angular 2 dynamic tabs with user-click chosen components kann ich dynamisch Komponenten hinzufügen, die den Typ übergeben.

Mein Problem ist, dass bei der Verwendung dieser Methode die erstellte Komponente nur durch ihren Typ erstellt wird und ich weiß nicht, wie man ihr Argumente gibt.

Dies ist, was ich getan habe:

container.component.ts

import { 
    Component, 
    OnChanges, 
    AfterViewInit, 
    OnDestroy, 
    Input, 
    Type, 
    ViewChild, 
    ViewContainerRef, 
    ComponentRef, 
    ComponentResolver, 
    ComponentFactory 
} from '@angular/core'; 

@Component({ 
    selector: 'wrapper-component', 
    template: '<div #container></div>' 
}) 
class WrapperComponent implements OnChanges, AfterViewInit, OnDestroy { 

    @Input() type: Type; 
    @ViewChild('container', {read: ViewContainerRef}) container; 

    cmpRef: ComponentRef<any>; 

    private isViewInitialized: boolean = false; 

    constructor(private resolver: ComponentResolver) { } 

    private updateComponent() { 
     if(!this.isViewInitialized) 
      return; 

     if(this.cmpRef) 
      this.cmpRef.destroy(); 

     this.resolver.resolveComponent(this.type).then((factory: ComponentFactory<any>) => { 
      this.cmpRef = this.container.createComponent(factory); 
     }) 
    } 

    ngOnChanges() { 
     this.updateComponent(); 
    } 

    ngAfterViewInit() { 
     this.isViewInitialized = true; 
     this.updateComponent(); 
    } 

    ngOnDestroy() { 
     if(this.cmpRef) 
      this.cmpRef.destroy(); 
    } 
} 

@Component({ 
    selector: 'container-component', 
    template: ` 
     <wrapper-component 
      *ngFor="let element of elements" 
      [type]="element"> 
     </wrapper-component> 
    `, 
    directives: [WrapperComponent] 
}) 
export class ContainerComponent { 

    private elements: Type[] = [];  

    visibility: boolean = true; 

    Add(element: Type) { 
     this.elements.push(element); 
    } 

    AddAll(elements: Type[]) { 
     elements.forEach(element => { 
      this.Add(element); 
     }); 
    } 

    Clear() { 
     this.elements = []; 
    } 
} 

a1.component.ts

import { Component, Type, ViewChild } from '@angular/core' 
import { ContainerComponent } from '../../components/container.component'; 

@Component({ 
    selector: 'child-component', 
    template: '<div>a{{text}}</div>' 
}) 
class ChildComponent { 
    text: string; 
} 

@Component({ 
    selector: 'a1step', 
    template: ` 
     <button (click)="onClick()">Add</button> 
     <container-component #container></container-component> 
    `, 
    directives: [ContainerComponent] 
}) 
export class A1Step { 
    @ViewChild('container') container : ContainerComponent; 

    onClick() { 
     this.container.Add(ChildComponent); 
    } 
} 

Hier kann ich dynamisch hinzufügen ChildComponents , aber wie kann ich seinen Text einstellen?

EDIT:

Ich weiß nicht, ob für andere nützlich sein könnte, aber ein Argument Klasse für den ChildComponent definieren und die Array-Elemente des ContainerComponent als ein Array von Objekten Aktualisierung der spezifische args enthalten, ich kann leicht bestimmte Argumente an die ChildComponents passieren:

container.component.ts

import { 
    Component, 
    OnChanges, 
    AfterViewInit, 
    OnDestroy, 
    Input, 
    Type, 
    ViewChild, 
    ViewContainerRef, 
    ComponentRef, 
    ComponentResolver, 
    ComponentFactory 
} from '@angular/core'; 

export class ChildArgs { 
    type: Type; 
    args: any; 
} 

@Component({ 
    selector: 'wrapper-component', 
    template: '<div #container></div>' 
}) 
class WrapperComponent implements OnChanges, AfterViewInit, OnDestroy { 

    @Input() argsElement: ChildArgs; 
    @ViewChild('container', {read: ViewContainerRef}) container; 

    cmpRef: ComponentRef<any>; 

    private isViewInitialized: boolean = false; 

    constructor(private resolver: ComponentResolver) { } 

    private updateComponent() { 
     if(!this.isViewInitialized) 
      return; 

     if(this.cmpRef) 
      this.cmpRef.destroy(); 

     this.resolver.resolveComponent(this.argsElement.type).then((factory: ComponentFactory<any>) => { 
      this.cmpRef = this.container.createComponent(factory); 
      this.cmpRef.instance.args = this.argsElement.args; 
     }) 
    } 

    ngOnChanges() { 
     this.updateComponent(); 
    } 

    ngAfterViewInit() { 
     this.isViewInitialized = true; 
     this.updateComponent(); 
    } 

    ngOnDestroy() { 
     if(this.cmpRef) 
      this.cmpRef.destroy(); 
    } 
} 

@Component({ 
    selector: 'container-component', 
    template: ` 
     <wrapper-component 
      *ngFor="let argsElement of argsElements" 
      [argsElement]="argsElement"> 
     </wrapper-component> 
    `, 
    directives: [WrapperComponent] 
}) 
export class ContainerComponent { 

    private argsElements: ChildArgs[] = []; 

    AddArgsElement(argsElement: ChildArgs) { 
     this.argsElements.push(argsElement); 
    } 
} 

a1.component.ts

import { Component, Type, ViewChild } from '@angular/core' 
import { ContainerComponent, ChildArgs } from '../../components/container.component'; 

class ChildComponentArgs { 
    text: string; 
} 

@Component({ 
    selector: 'child-component', 
    template: '<div>a{{args.text}}</div>' 
}) 
class ChildComponent { 
    args: ChildComponentArgs; 
} 

class ChildComponent2Args { 
    text: string; 
} 

@Component({ 
    selector: 'child-component2', 
    template: '<div>b{{args.text}}</div>' 
}) 
class ChildComponent2 { 
    args: ChildComponent2Args; 
} 

@Component({ 
    selector: 'a1step', 
    template: ` 
     <button (click)="onClick()">Add</button> 
     <button (click)="onClick2()">Add2</button> 
     <container-component #container></container-component> 
    `, 
    directives: [ContainerComponent] 
}) 
export class A1Step { 
    @ViewChild('container') container : ContainerComponent; 

    private cnt: number = 0; 
    private cnt2: number = 0; 

    onClick() { 
     let childComponentArgs: ChildComponentArgs = new ChildComponentArgs(); 
     childComponentArgs.text = "" + ++this.cnt; 

     let childArgs: ChildArgs = new ChildArgs(); 
     childArgs.type = ChildComponent; 
     childArgs.args = childComponentArgs; 

     this.container.AddArgsElement(childArgs); 
    } 

    onClick2() { 
     let childComponentArgs: ChildComponent2Args = new ChildComponent2Args(); 
     childComponentArgs.text = "" + ++this.cnt2; 

     let childArgs: ChildArgs = new ChildArgs(); 
     childArgs.type = ChildComponent2; 
     childArgs.args = childComponentArgs; 

     this.container.AddArgsElement(childArgs); 
    } 
} 

Antwort

5

Sie können die erstellten Komponenteninstanz cmpRef.instance mit Zugriff:

this.resolver.resolveComponent(this.type).then((factory: ComponentFactory<any>) => { 
     this.cmpRef = this.container.createComponent(factory); 
     this.cmpRef.instance.text = this.someText; 
    }) 

Siehe auch Angular 2 dynamic tabs with user-click chosen components für ein volles Beispiel.

+1

danke, das funktioniert. – pasianos

Verwandte Themen