Angular 2 ngFor中不同组件的列表

Arū*_*kas 11 javascript angular

我知道有很多类似的问题,几乎所有问题都以DynamicComponentLoader答案结束,但我认为下面描述的用例是如此简单和常见(IMO),Angular 2的解决方案应该是直截了当的.

示例用例

我有一系列新闻项目,其属性type描述了它是什么类型的项目.

var items = [
  { id: 1, type: 'text', data: {} },
  { id: 2, type: 'text', data: {} },
  { id: 3, type: 'text-two-columns', data: {} },
  { id: 4, type: 'image-text', data: {} },
  { id: 5, type: 'image', data: {} },
  { id: 6, type: 'twitter', data: {} },
  { id: 7, type: 'text', data: {} }
]
Run Code Online (Sandbox Code Playgroud)

每种不同的类型都有不同的view,完全不同的逻辑.换句话说 - 每个type都有自己的angular2 Component.

所以我试图实现的抽象代码是:

<div *ngFor="let item of items">
   <item-{{item.type}} [data]="item.data"></item-{{item.type}}>
</div>
Run Code Online (Sandbox Code Playgroud)

当然它不会起作用.

可能的解决方案#1

<div *ngFor="let item of items">
   <item-text *ngIf="item.type === 'text'" [data]="item.data"></item-text>
   <item-image *ngIf="item.type === 'image'" [data]="item.data"></item-image>
   ...
</div>
Run Code Online (Sandbox Code Playgroud)

我不喜欢这个解决方案不仅因为它看起来很丑陋而且我每次添加新类型时都必须包含这一行但是我想知道这个解决方案从性能角度来看是否合适?我的意思是,如果我有10,000种不同的类型,只显示3个项目.因此angular2必须从DOM中删除9,999个标签,并且每个3个项目只留下一个(3*9999删除操作).

可能的解决方案#2

<div *ngFor="let item of items">
   <dynamic-component-loader [item]="item"></dynamic-component-loader>
</div>
Run Code Online (Sandbox Code Playgroud)

目前我不记得究竟是如何DynamicComponentLoader工作的(我在很久以前在angular2 alpha的类似问题中尝试过它).但是我记得代码看起来hack对我来说..对于这样的常见任务?...

Angular 1.x思考

我不知道我做错了什么,也许问题是我还在想Angular 1?使用它我会使用ngInclude或自定义指令与模板功能.

伙计们,你有其他解决方案吗?不要坚持我的两个可能的解决方案,也许我需要开箱即用,并在我的应用程序的不同部分完全解决这个问题.我很困惑.谢谢:)

编辑:一个更真实的例子

假设您的任务是使用Angular 2编写Facebook.我认为您在尝试显示新闻源时会遇到同样的问题.每个新闻源项目有它的类型(text,event,ads,...)

Tuo*_* Le 6

这是我的解决方案:

import { Component, OnInit, ViewContainerRef, TemplateRef, ComponentFactoryResolver, Input } from '@angular/core';

@Component({
  selector: 'item',
  template: '',
  styleUrls: ['./item.component.scss']
})
export class ItemComponent implements OnInit {
  @Input() type: string;
  @Input() data: any;

  constructor(
    private viewContainerRef: ViewContainerRef,
    private componentFactoryResolver: ComponentFactoryResolver,
    private componentLookupService: YourComponentLookUpService
  ) { }

  ngOnInit() {
    const component = this.componentLookupService.findByType(type);
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(component);
    // Look at the https://angular.io/docs/ts/latest/api/core/index/ViewContainerRef-class.html#!#createComponent-anchor for more information about how to use DI... in the createComponent function.
    const componentRef =this.viewContainerRef.createComponent(componentFactory);
    // Or you can then access the newly created component here: this.componentRef.instance
  }

}
Run Code Online (Sandbox Code Playgroud)

在你的NgFor循环中:

<div *ngFor="let item of items">
   <item [type]="item.type" [data]="item.data"></item>
</div>
Run Code Online (Sandbox Code Playgroud)


Nor*_*ins 5

我会写另一个组件,说item-flex

<item-flex [item]="item" *ngFor="let item of items"></item-flex>
Run Code Online (Sandbox Code Playgroud)

item-flex可以使用ngSwitch

<div [ngSwitch]="item.type">
    <item-text *ngSwitchCase="'text'" [data]="item.data"></item-text>
    <item-image *ngSwitchCase="'image'" [data]="item.data"></item-image>
    <span *ngSwitchDefault >UNKNOWN TYPE:{{item.type}}</span>
</div>
Run Code Online (Sandbox Code Playgroud)

或“丑陋的ifs”(通过这种方式,您甚至可以摆脱ngSwitch解决方案中存在的外部标记/ div / span ):

<item-text *ngIf="item.type=='text'" [data]="item.data"></item-text>
<item-image *ngIf="item.type=='image'" [data]="item.data"></item-image>
Run Code Online (Sandbox Code Playgroud)


Ano*_*aac 5

我想您可以使用 Angular 4 附带的“ngComponentOutlet”,它根据传递的值动态创建组件。我还没有测试过代码。

@Component({
    selector: 'my-app',
    template: `
    <h1>Angular version 4</h1>
    <div *ngFor="let <component name> of <list of component name>">
        <ng-container *ngComponentOutlet="<component name>">enter code here</ng-container>
    </div>
  `,
})
Run Code Online (Sandbox Code Playgroud)

请参考网址了解更多详情:https : //netbasal.com/a-taste-from-angular-version-4-50be1c4f3550