2017-08-30 14 views
5

Co usiłuję zrobić

Pracuję na systemie głos, który zostanie ponownie wykorzystany w wielu komponentów na całym stronie. Aby zachować suchość, chcę utworzyć komponent głosowania z dowolnego komponentu, do wyznaczonego elementu DOM. Po utworzeniu składnika należy ustawić zmienne instancji (w tym przypadku model:string i pk:number, oba publiczne).NG4 componentFactory umieszczenie go w docelowej DOM

wynik Oczekiwany

Spodziewam składnik być wykonane w wyznaczonym miejscu, drukowanie odpowiednich danych, które zostały tuż po fabryka stworzyła komponent. Wyjście na dole głosów powinna być Model: project PK: 1

rzeczywista sytuacja

ComponentFactory obecnie dwa wyjść składowej głosowania utworzonego przez komponent fabryczne:

  1. Na właściwym miejscu (ukierunkowane div), ale bez ustawionych zmiennych instancji. image1

  2. U dołu strony, ale jest to inny problem, w późniejszym czasie i na inny temat.

Niektóre kod

@NgModule({ 
    .. 
    declarations: [ 
     AppComponent, 
     ProjectComponent, // parent for voteContainer 
     VoteComponent, // Dynamic component 
    ], 
    entryComponents: [ 
     VoteComponent, 
    ], .. 
}) 

składnikiem dominującym zawierający fabrykę VoteComponent

export class ProjectDetailComponent implements AfterViewInit { 
    @ViewChild('voteComponentContainer', {read: ViewContainerRef}) voteComponentContainer; 

    public ngAfterViewInit() { 
     this.factoryVoteComponent(); 
    } 

    private factoryVoteComponent() { 
     const voteComponentFactory = this.componentFactoryResolver.resolveComponentFactory(VoteComponent); 
     const voteComponentRef = this.viewContainerRef.createComponent(voteComponentFactory); 
     voteComponentRef.instance.model = "project"; 
     voteComponentRef.instance.pk = 1; 
     voteComponentRef.changeDetectorRef.detectChanges(); 
    } 
} 

Dynamiczny cel komponent:

<vote-component-container></vote-component-container> 

podstawowy składnik głosowanie

@Component({ 
    selector: 'vote-component-container', 
    templateUrl: 'vote.component.html', 
}) 

export class VoteComponent { 
    public model:string; 
    public pk:number; 
    public constructor(){} 
} 

Co Próbowałem

mam zmaga się z tym przez jakiś czas teraz, więc nie są dość pewne próby zmusić go do pracy. Ostatnia próba to z utworzeniem ViewChild dla fabryki.

Poza tym, ja już zostały gry z nazwami, różne sposoby konfigurowania odbiornika szablon komponentu itp

Co chcę zapytać

Czy ktoś ma jakieś doświadczenia z wykorzystanie dynamicznych komponentów, jak w sytuacji, którą próbuję teraz? Miałem nadzieję, że pchnę we właściwym kierunku, jak rozwiązać kwestię renderowanego komponentu we właściwej lokalizacji, ale bez dostępnych atrybutów.

+0

Jeśli zainicjujesz zmienne z wartością domyślną w komponencie VoteComponent, a następnie spróbujesz je ustawić po utworzeniu, czy to działa? np ---> public pk: number = 0; model publiczny: string = ''; <--- – diopside

+1

Należy również pamiętać, że podczas tworzenia komponentów dynamicznych są one tworzone jako * rodzeństwo * w obiekcie ViewContainerRef służącym do ich umieszczania. Nie jako dziecko. Więc jeśli używasz ViewChild, aby umieścić je w elemencie component, zostanie on renderowany zaraz po tym kontenerze, a nie w nim. To spowodowało wiele zamieszania, kiedy po raz pierwszy zacząłem pracować w dynamicznych komponentach! – diopside

Odpowiedz

0

Po dalszych badaniach, testowanie zawiodło i próbowałem czegoś więcej - znalazłem rozwiązanie.Nie jestem jeszcze w 100% zadowolony, ponieważ staje się trochę mniej suchy i zorganizowany - ale na razie:

Najpierw musiałem dostosować sposób przekazywania moich danych do dynamicznie generowanego komponentu. Musiałem zaktualizować cel selektora, aby zaakceptować wymagane atrybuty. W moim przypadku model i objectId.

<vote-component-container [model]="'project'" [objectId]="projectId"></vote-component-container> 

Aby połączyć te dane do VoteComponent sama VoteComponent potrzebuje @Input ustawiające dla tych danych wejściowych, takich jak:

import { Input, Component, AfterViewInit } from '@angular/core'; 

@Component({ 
    selector: 'vote-component-container', 
    templateUrl: 'vote.component.html', 
}) 

export class VoteComponent implements AfterViewInit { 
    // Temp public for testing 
    public _objectId:number; 
    public _model:string; 

    public constructor(){} 
    public ngAfterViewInit(){ 
     this.getVotes(); 
    } 

    @Input('objectId') 
    set objectId(objectId:number){ 
     this._objectId = objectId; 
    } 

    @Input('model') 
    set model(model:string){ 
     this._model = model; 
    } 

    public getVotes(){ 
     ... 
    } 
} 

i ostatecznie w moim elementu nadrzędnego, spodziewałem params [ 'id'] sekcja była wtedy, gdy funkcja została wywołana w ngAfterInit. Ale tak się nie stało, więc musiałem poczekać na obietnicę ..

@ViewChild('voteComponentContainer', {read: ViewContainerRef}) target: ViewContainerRef; 
private factoryVoteComponent(){ 
    this.activatedRoute.params.subscribe((params: Params) => { 
     this.model = 'project'; 
     this.projectId = params['id']; 

     let voteComponentFactory = this.componentFactoryResolver.resolveComponentFactory(VoteComponent); 
     this.voteComponentRef = this.viewContainerRef.createComponent(voteComponentFactory); 
     this.voteComponentRef.changeDetectorRef.detectChanges(); 
    }); 
}