来自共同来源的 Angular 条件分量

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

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

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

提要项目的基本形状类似于:

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
    }
    }
]

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

我想要做的是有一个 Angular 组件,负责从 API 获取提要项目列表并循环访问提要项目。对于每个 feed 项(大概在 *ngFor 指令中),它应该呈现公共(public)属性,然后根据 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 容器组件。

那么,这可能吗?如果是这样,我该怎么办?

最佳答案

如果我能正确理解的话,也许下面的想法可以帮助你。 我以你的例子为例并稍加修改。

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

如果你只有两种类型(我对此表示怀疑),你也可以这样做:

<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>

希望有帮助:)

关于来自共同来源的 Angular 条件分量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53693053/

相关文章:

typescript - 属性 'trimLeft' 在类型 'string' 上不存在。库 : ["dom", "es2018"]

angular - 访问 typescript 中给定属性名称的数组

javascript - Uncaught Error : Nothing handled the action 'edit'

javascript - 在 Angular 中动态更新 SVG

angular - Ionic 5 中 CanDeactivate 守卫的导航问题

javascript - 通过数组在 Ionic/Angular ngFor 中遇到问题

javascript - 无法解析 ApplicationModule : (? 的所有参数)- Angular 7 JIT

angular - 在 APP_INITIALIZER 完成之前调用 APP_BASE_HREF token 的 Providerfactory

angular - 我怎样才能在 typescript 中导入 d3-selection-multi

javascript - DurandalJS 路由行为