【问题标题】:In Angular2 *ngFor iteration, how do I output only unique values from the array?在 Angular2 *ngFor 迭代中,如何仅输出数组中的唯一值?
【发布时间】:2017-06-11 13:39:53
【问题描述】:

它有内置管道吗?

data = [
  {id: 5, name: 'Roger'},
  {id: 5, name: 'Mark'},
  {id: 5, name: 'Zach'},
  {id: 5, name: 'Mark'},
  {id: 5, name: 'Roger'},
];

<ul>
  <li *ngFor="let datum of data">
    {{datum.name}}
  </li>
</ul>

Output

  • 罗杰
  • 马克
  • 扎克
  • 马克
  • 罗杰

Desired Output

  • 罗杰
  • 马克
  • 扎克

【问题讨论】:

  • 感谢您的提问和回答。我有一个附加功能的相同目标。假设每个项目都有一个名为 mark 的属性,如果重复存在带有标记总和的显示名称,则过滤唯一名称。有什么想法吗?

标签: angular


【解决方案1】:

您可以创建自己的管道。

import { Pipe, PipeTransform } from '@angular/core';
import * as _ from 'lodash'; 

@Pipe({
  name: 'unique',
  pure: false
})

export class UniquePipe implements PipeTransform {
    transform(value: any): any{
        if(value!== undefined && value!== null){
            return _.uniqBy(value, 'name');
        }
        return value;
    }
}

您需要在组件中添加 UniquePipe,然后在 HTML 文件中添加管道。

<ul>
  <li *ngFor="let datum of data | unique">
    {{datum.name}}
  </li>
</ul>

【讨论】:

  • @anonym 你能用你的修改更新答案吗
  • 仅供参考,这可行,但过滤是 Angular 团队明确建议您不要在管道中执行的操作,以及排序。在每个变更检测周期都会触发管道,如果此列表很长,这将成为性能问题的根源。您在这里使用了 lodash 来掩盖很多列表迭代,但事实是这里的大 O 是 n^2。过滤应该在代码中完成,并在需要触发时触发。在您的组件中添加一个 ngChanges 挂钩并登录到其中的控制台以查看触发更改检测的频率。
  • 我应该在哪里创建自己的管道,我需要在 app.module.ts 或 app.component.ts 中导入它吗?
  • 我认为你应该创建通用模块并创建新的管道目录。而不是你应该将你的公共模块导入你的应用程序模块。
【解决方案2】:

这有点老了,但我想为以后发现这个的人添加一个答案。

接受的答案建议使用实现目标的管道,但在这种情况下,这不是推荐的方法。这里我们谈论的是一个列表过滤器,一个非常具体的重复过滤器。此操作的最坏情况 big O 可能接近 n^2 或相当占用内存(取决于您的方法)。 由于角度管道的运行方式以及不纯管道操作在每个更改检测周期中执行,并且 Angular 中的更改检测非常频繁地触发,因此该特定管道可能会被标记为“不纯”**(就像在接受的答案中一样)。如果这个列表很长,或者如果您对此进行了练习,那么您的应用程序将停止运行,并且您将遇到明显的性能问题。

**如果你不将管道标记为不纯,那么如果你曾经对数组进行变异,操作将不会运行,虽然避免数组变异是好的做法,但在这种情况下,它是一个隐藏的依赖项,并且通常是不好的做法。

Angular 1 实际上包含一个“过滤器”管道,但团队选择在 Angular 2 中去掉它,因为过滤器管道的滥用导致人们将这种不良做法导致的性能问题归咎于 Angular 1。管道用于非常小的数据转换,例如格式化数字或字符串。

您应该这样做的方式是在代码中过滤您的列表,并构建逻辑来触发您自己的过滤(例如,当您的列表实际更改时),而不是依赖更改检测来为您执行此操作。在这种情况下很难准确地说出如何做到这一点,因为它是非常特定于用例的,如果您希望您的应用程序运行良好,就应该这样做。一个相当通用的示例是,如果此列表来自可观察的流(应该如此),那么只需在 map 运算符中执行此操作并像这样使用 async:

dataSource = Observable.of(data); //this is just for example, the actual data source should be an http call or some service layer subject that you can actually update / trigger    
uniqueData$ = this.dataSource.map(data => _.uniqBy(data, 'name'));

<ul>
  <li *ngFor="let datum of uniqueData$ | async">
    {{datum.name}}
  </li>
</ul>

这里的优点是过滤操作仅在可观察流触发时触发,因此您对过滤何时发生具有非常高的控制权,并且仍然很容易推理并且非常“肯定会正确发生”

【讨论】:

    猜你喜欢
    • 2016-11-01
    • 1970-01-01
    • 2017-11-08
    • 1970-01-01
    • 1970-01-01
    • 2017-03-08
    • 1970-01-01
    • 1970-01-01
    • 2017-08-13
    相关资源
    最近更新 更多