0

I build a simple List UI component, which contains items, which are also components:

AppComponent -> ListComponent -> ListItemComponent

I want this list to visualize different types of list item components.

For example 2 types of list items:

 @Component({
   selector: 'list-item',
   template: 'This is a PRODUCT!'
 })
 export class ProductListItemComponent { }
 @Component({
   selector: 'list-item',
   template: 'This is a PERSON!'
 })
 export class PersonListItemComponent { }

So, when I initialize my app component:

 import {ListComponent} from '...';
 import {ProductListItemComponent} from '...';

 @Component({
   selector: 'list-item',
   template: `
     <list></list>
   `,
   directives: [
     ListComponent,
     ProductListItemComponent
   ]
 })
 export class AppComponent { }

It doesn't work (of course), because my ListComponent do not receive item component (directive) from app component.

 @Component({
   selector: 'item',
   template: `
     <ul><li *ngFor=...>
       <list-item></list-item>
     </li></ul>
   `
 })
 export class ListComponent { }

What should I do, how make it work? Thank you in advance!

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
Vladimir
  • 361
  • 1
  • 3
  • 14

2 Answers2

0

First of all - does it your real code or copy-paste? Because I see, that almost all of your components have the same selector 'list-item', which is wrong.. it should be uniq.

And the second, about the problem by itself - you should add ProductListItemComponent and PersonListItemComponent deps right to your ListComponent if you want them to render inside list. Like this:

import {PersonListItemComponent} from '...';
import {ProductListItemComponent} from '...';

@Component({
 selector: 'list',
 template: `
   <ul><li *ngFor=...>
    <list-item></list-item>
   </li></ul>
 `,
 directives: [
   PersonListItemComponent,
   ProductListItemComponent
 ]
})
export class ListComponent { ...}

and for your AppComponent you need to add for 'directives' prop only ListComponent

Oleg Barinov
  • 1,635
  • 12
  • 7
  • If I would do like in your example indeed I should give them different selectors, but if I would pass the component dynamically than (I guess) they could be identical. – Vladimir Aug 16 '16 at 16:42
  • Please check my solution. In the final version there is no selectors at all! – Vladimir Aug 17 '16 at 17:00
0

So, here is the final version, which I build based on Angular 2 dynamic tabs with user-click chosen components (Thank you Gunter!)

The solution is to use a dynamic component as an intermediate between List and List Items of different types.

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

@Component({
  selector: 'dynamic-list-item',
  template: `<div #target></div>`
})
export class DynamicListItem {

  @ViewChild('target', {read: ViewContainerRef}) target;
  @Input() Type: any;
  @Input() Item: any;
  cmpRef: ComponentRef<any>;
  private isViewInitialized: boolean = false;

  constructor(private resolver: ComponentResolver) { }

  updateComponent() {
    if(!this.isViewInitialized) return;
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }
    this.resolver.resolveComponent(this.Type).then((factory:ComponentFactory<any>) => {
      this.cmpRef = this.target.createComponent(factory);
      this.cmpRef.instance.Item = this.Item;
    });
  }

  ngOnChanges() {
    this.updateComponent();
  }

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

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

}

Plunker example RC4

Community
  • 1
  • 1
Vladimir
  • 361
  • 1
  • 3
  • 14