【问题标题】:Angular conditional components from a common source来自公共来源的 Angular 条件组件
【发布时间】:2019-05-10 14:36:18
【问题描述】:

首先,我想提一下,我不是 Angular 开发人员,几乎我所有的技能都属于后端工作,但我正在努力解决这个概念,我什至不知道它是否可能的。谷歌搜索没有多大帮助,因为我什至不知道如何正确表达这个问题,所以我希望描述这种情况,我想做什么,我希望它如何工作,并希望得到一些关于我正在尝试做的事情的建议实际上是在 Angular 世界中调用的,无论它是否可能,假设它是可能的,它会是什么样子的一个例子。

我们有一个具有 .NET Core Web API 后端的 SPA。有一个 API 端点 /api/feedItems,它返回一个“提要项”列表,大致相当于事件日志。

Feed 项的基本形状如下所示:

export enum FeedItemType {
    undefined = "undefined",
    foo = "foo",
    bar = "bar"
}

export class FeedItemModel {
    id: number;
    createdUtcTimestamp: Date;
    feedType: FeedItemType;
    feedData: {} // object? any?
}

这里的想法是,所有提要项都将具有某些元数据,包括 id、时间戳、提要类型标识符和有效负载。实际有效载荷内容将根据FeedItemType而有所不同。

从 API 调用返回的示例提要项列表可能类似于以下内容:

[  
    {  
    "id":12345,
    "createdUtcTimestamp":"2018-12-05T13:30:00Z",
    "feedType":"foo",
    "feedData":{  
        "name":"this is a foo type feed",
        "description":"This foo feed is describing an event of type 'foo'"
    }
    },
    {  
    "id":67890,
    "createdUtcTimestamp":"2018-12-06T15:45:00Z",
    "feedType":"bar",
    "feedData":{  
        "value1":11111,
        "value2":22222,
        "value3":33333
    }
    }
]

我们实际上有很多不同的提要项类型,每种类型都应该有自己的自定义渲染,以便以最有用的方式可视化数据。

我想要做的是有一个角度组件,负责从 API 获取提要项目列表并循环访问提要项目。对于每个提要项(可能在*ngFor 指令中),它应该呈现公共属性,然后基于feedType,呈现不同的“子”组件。

在这种情况下,假设我的容器组件如下所示:

<div class="feed-item-container" *ngFor="let feedItem of feedItemList; let i = index;">
    <div class="feed-item">
        <div class="timestamp-display">{{feedItem.createdUtcTimestamp}}</div>

        <!-- equivalent of "if feedItem.feedType == 'foo'", 
        possibly ngIf or ngSwitch, but I'd prefer to not 
        have to explicitly check for each type -->
        <feed-item-foo (I have no idea how to pass the feedData to this component) />

        <!-- equivalent of "if feedItem.feedType == 'bar'" -->
        <feed-item-bar (again, this is a mystery what should go here) />

        <!-- equivalent of "if can't match on feedType" -->
        <feed-item-generic (something) />
    </div>
</div>

这里的想法是,我可以根据需要在此文件之外创建组件,而无需对容器模板进行很多更改(最好没有更改)。如果我能以编程方式识别feedType,为其查找已注册的组件选择器,并自动将feedData 传递给它,那将是理想的,但如果我必须手动引用此容器中的每个组件,那也没关系。我只是不想将所有的渲染逻辑都放在这个容器中,因为那样会很快变得笨重且难以管理。

提要项组件将根据提要类型有自己的格式,也有不同的样式,可能还有不同的逻辑操作。我不想要一个巨大的 feedItem 容器组件。

那么,这可能吗?如果是这样,我会怎么做?

【问题讨论】:

  • 无论你现在做什么,你都需要一些 switchif/elsesomewhere。一个通用的feed-item 组件,它只决定一个具体的feed-item 进行渲染是一个完美的解决方案,对性能没有影响并且容易理解。要传入数据,请使用常规输入:&lt;feed-item-foo [foo]="feedItem"&gt;。在FeedItemFooComponent 本身中为其提供适当的类型信息,例如@Input() foo: FeedItemFoo,然后就可以开始了。

标签: angular typescript single-page-application angular-components


【解决方案1】:

如果我能正确理解,也许下面的想法可以帮助你.. 我拿你的例子做了一点修改。

<div class="feed-item-container" *ngFor="let feedItem of feedItemList; let i = index;">
<div class="feed-item">
    <div class="timestamp-display">{{feedItem.createdUtcTimestamp}}</div>

    <!-- equivalent of "if feedItem.feedType == 'foo'", 
    possibly ngIf or ngSwitch, but I'd prefer to not 
    have to explicitly check for each type -->

    <!-- i do not know of any alternative, but to make it a bit more readable
    you can use <ng-container>

    <ng-container *ngIf="feedItem.feedType === 'foo'">
        <!-- you can create your own component and add an @Input() data, so your component will know what it is dealing with (see example below)
        <feed-item-foo [data]="feedItem"/>
    </ng-container>

    <!-- equivalent of "if feedItem.feedType == 'bar'" -->
    <ng-container *ngIf="feedItem.feedType === 'bar'">
        <!-- you can create your own component and add an @Input() data, so 
        your component will know what it is dealing with (see example below)
        <feed-item-bar [data]="feedItem"/>
    </ng-container>
    <!-- equivalent of "if can't match on feedType" -->
    <!-- that is a bit of a pain in the ... --> 
   <ng-container *ngIf='!foo && !bar && !xyz'>
    <feed-item-generic (something) />
   </ng-container>

</div>

您的组件可以而且应该都包含类似“基”类的东西

export class FeedItemBase implements OnInit {
  @Input() data = <YourType>null; // that is a little hack to get the type 
  // correct (was some bug in a angular 4 version as far as i remember)
  constructor() {
  }
  ngOnInit() {
    // if needed .. if not, delete it :)
  }
}

那么你所有的其他类都可以扩展基类(因为数据总是相同的......

export class FeedItemFoo extends FeedItemBase implements OnInit {
  constructor() {
  }
  ngOnInit() {
    // here you can access data already 
  }
}

如果你只有 2 种类型(我怀疑),你也可以这样做:

<div class="feed-item-container" *ngFor="let feedItem of feedItemList; let i = index;">
<div class="feed-item">
    <div class="timestamp-display">{{feedItem.createdUtcTimestamp}}</div>

    <!-- equivalent of "if feedItem.feedType == 'foo'", 
    possibly ngIf or ngSwitch, but I'd prefer to not 
    have to explicitly check for each type -->

    <!-- i do not know of any alternative, but to make it a bit more readable
    you can use <ng-template>
    <ng-container *ngIf="feedItem.feedType === 'foo'; then fooId;else barId"> 
    </ng-container>

   <ng-template #fooId>
        <!-- you can create your own component and add an @Input() data, so your component will know what it is dealing with (see example below)
        <feed-item-bar [data]="feedItem"/>
    </ng-template>

    <!-- equivalent of "if feedItem.feedType == 'bar'" -->
    <ng-template #barId>
        <!-- you can create your own component and add an @Input() data, so 
        your component will know what it is dealing with (see example below)
        <feed-item-foo [data]="feedItem"/>
    </ng-container>
    <!-- equivalent of "if can't match on feedType" -->
    <!-- that is a bit of a pain in the ... --> 
   <ng-container *ngIf='!foo && !bar && !xyz'>
    <feed-item-generic (something) />
   </ng-container>

</div>

希望对你有帮助:)

【讨论】:

  • 确实有帮助,谢谢。在这和@Lazar 的评论之间,我想我对该怎么做有一个不错的了解。
猜你喜欢
  • 1970-01-01
  • 2022-11-05
  • 2011-08-13
  • 1970-01-01
  • 1970-01-01
  • 2013-07-09
  • 2020-11-22
  • 2023-03-15
  • 2020-09-28
相关资源
最近更新 更多