Angular2 在 Subchild 中传递指令

Angular2 pass directive in Subchild

我构建了一个简单的列表 UI 组件,其中包含项目,这些项目也是组件:

AppComponent -> ListComponent -> ListItemComponent

我希望此列表可视化不同类型的列表项组件。

例如 2 种类型的列表项:

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

所以,当我初始化我的应用程序组件时:

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

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

它不起作用(当然),因为我的 ListComponent 没有从应用程序组件接收项目组件(指令)。

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

我该怎么办,怎么办? 提前致谢!

首先 - 它是您的真实代码还是复制粘贴?因为我看到,几乎所有组件都有相同的选择器 'list-item',这是错误的。它应该是 uniq。

第二,关于问题本身 - 如果您希望它们在列表中呈现,您应该将 ProductListItemComponentPersonListItemComponent dep 添加到 ListComponent 中。像这样:

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 { ...}

并且对于您的 AppComponent,您只需要为 'directives' prop 添加 ListComponent

所以,这是我基于 构建的最终版本(谢谢 Gunter!)

解决方案是使用动态组件作为不同类型的列表和列表项之间的中间。

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