2017-06-29 5 views
1

J'ai essayé de faire une vue de l'onglet et de la pensée projection de contenu pourrait être une bonne approach.I appris de cette article. J'ai pensé que je pourrais le rendre dynamique en entrant simplement un tableau donné de composants, et ils seraient affichés en tant que page pour l'onglet sélectionné.angulaire 2- ContentChidren de composant parent ne sont pas définies lors de la création dynamique composant enfant

Voici ma tentative de faire ceci:

@Component({ 
    selector: 'my-app', 
    template:` 
    <h1>Experiments</h1> 
    <button class="add-button" (click)="add()">Add</button>` 
}) 
export class App { 

    components:Array<any> = [PrepSetupTab,FinalizeTab] 

    constructor(private cdr: ChangeDetectorRef, 
       private compFR: ComponentFactoryResolver, 
       private viewContainer: ViewContainerRef){} 

    add():void{ 
     var transTabRefs: Array<any>= [] 

     this.components.forEach(tabComponent=>{ 

      let compFactory = this.compFR.resolveComponentFactory(tabComponent); 
      let compRef = this.viewContainer.createComponent(compFactory); 
      let tabFactory = this.compFR.resolveComponentFactory(Tab); 

      let transcludedTabRef = this.viewContainer.createComponent(tabFactory,this.viewContainer.length - 1, undefined, [[compRef.location.nativeElement]]); 
      transTabRefs.push(transcludedTabRef.location.nativeElement); 
     }) 

     let tabsFactory = this.compFR.resolveComponentFactory(Tabs); // notice this is the tabs not tab 
     this.viewContainer.createComponent(tabsFactory,0,undefined,[transTabRefs]); 

    } 


} 

Side note, ajouter() en tant que gestionnaire de clic de bouton ne vise pas la fonctionnalité autre pour éviter ce bug: "EXCEPTION: Expression has changed after it was checked". Je reçois ce bug si je le mets dans n'importe quel crochet de cycle de vie. Bien que ce soit un défi à traiter plus tard cependant.

Donc, fondamentalement, je crée le chaque composant dans le tableau, puis je les coller dans comme ng contenu pour chaque composant créé Tab. Ensuite, prenez chaque composant Tab et collez-le dans ng-content pour le composant Tabs.

Le problème est Tabs Component ne trouve jamais les contentChildren des enfants Tab créées dynamiquement. Voici le code du composant Tabs où les enfants du contenu ne sont pas définis.

@Component({ 
    selector: 'tabs', 
    template:` 
    <ul class="nav nav-tabs"> 
     <li *ngFor="let tab of tabs" (click)="selectTab(tab)" [class.active]="tab.active"> 
     <a>{{tab.title}}</a> 
     </li> 
    </ul> 
    <ng-content></ng-content> 
    ` 
}) 
export class Tabs implements AfterContentInit { 

    @ContentChildren(Tab) tabs: QueryList<Tab>; 

    // contentChildren are set 
    ngAfterContentInit() { 
    // get all active tabs 
    let activeTabs = this.tabs.filter((tab)=>tab.active); 

    // if there is no active tab set, activate the first 
    if(activeTabs.length === 0) { 
     this.selectTab(this.tabs.first); 
    } 
    } 

    selectTab(tab: Tab){ 
    // deactivate all tabs 
    this.tabs.toArray().forEach(tab => tab.active = false); 

    // activate the tab the user has clicked on. 
    tab.active = true; 
    } 

} 

Il me semble assez clair que le composant onglet est créé à un autre moment, puis quand j'ai besoin d'y accéder en tant qu'enfants contenu de la composante onglets. J'ai également essayé d'utiliser le ChangeDetectionRef.changeDetect() mais cela n'aide pas.

Peut-être que tout cela à travers la projection de contenu n'est pas le moyen le plus simple ou le meilleur, donc je suis ouvert aux suggestions. Voici le plunk, merci!

+0

'@ ContentChildren' ne fonctionnera pas avec le composant de création dynamique. C'est par conception – yurzui

+0

http://plnkr.co/edit/t1GnzDDR2s5g8PSDojXv?p=preview – yurzui

+0

Wow, InitContent Je n'ai pas vu celui-là avant! Et en y réfléchissant, vous pourriez reconnaître une partie de ce code, puisque je pense que je l'ai eu d'un plunk précédent :). –

Répondre

0

@ContentChildren ne fonctionnera pas pour les composants créés dynamiquement.

Pourquoi?

C'est parce que les candidats pour la projection doivent être connus au moment de la compilation.

Voici la fonction qui est utilisée pour calculer ContentChildren

function calcQueryValues(view, startIndex, endIndex, queryDef, values) { 
    for (var /** @type {?} */ i = startIndex; i <= endIndex; i++) { 
     var /** @type {?} */ nodeDef = view.def.nodes[i]; 
     var /** @type {?} */ valueType = nodeDef.matchedQueries[queryDef.id]; 
     if (valueType != null) { 
      values.push(getQueryValue(view, nodeDef, valueType)); 
     } 

Il utilise des nœuds qui sont déclarés dans viewDefinition pour le composant. Lorsque vous avez créé le composant tabs via createComponent et que vous avez passé manuellement des nœuds pouvant être projetés, vous n'avez pas modifié viewDefinition factory pour le composant tabs et donc angulaire ne sera pas informé des nœuds dynamiques.

Une solution possible pourrait être initialiser manuellement vos onglets

Vous pouvez l'observer dans cette Plunkr

0

Jetez un coup d'oeil sur l'exemple que je donne ici dynamically add elements to DOM, peut-être vous trouverez quelque chose utile pour votre problème. À ce stade de votre plnkr, le tableau des onglets est vide.