如何在应用管道后查找ngFor中的项目数

时间:2016-03-17 23:45:54

标签: angular angular2-directives

我有一个ngFor在表中创建过滤和分页的行。

<tr *ngFor="#d of data.results | filter:filterText | pagination:resultsPerPage:currentPage">

页面上还有另一个元素显示显示的记录数。这些元素最初绑定到数据。结果&#39;长度。

如何获取应用过滤器管道后显示的数据长度,以便我可以正确显示它。 ngFor中提供的局部变量似乎都没有考虑到这一点。

9 个答案:

答案 0 :(得分:13)

一种方法是使用@ViewChildren()

的模板变量
<tr #myVar *ngFor="let d of data.results | filter:filterText | pagination:resultsPerPage:currentPage">
@ViewChildren('myVar') createdItems;

ngAfterViewInit() {
  console.log(this.createdItems.toArray().length);
}

答案 1 :(得分:7)

您可以通过在管道中转换数组来获取项目的计数。

这个想法是管道会将数组转换为另一个数组,其中每个元素都有一个item属性,以及一个表示过滤(或原始)数组的父属性:

@Pipe({ name: 'withParent', pure: false })
export class WithParentPipe implements PipeTransform {
    transform(value: Array<any>, args: any[] = null): any {

        return value.map(t=> {
            return {
                item: t,
                parent: value
            }
        });
    }
} 

以下是如何使用它:

 <tr *ngFor="#d of data.results | 
        filter:filterText |
        pagination:resultsPerPage:currentPage | 
        withParent">
        Count:  {{d.parent.length }}
        Item:  {{ d.item.name}}
 </tr>

答案 2 :(得分:7)

这不是原始问题的目的,但我也在寻找一种方法来显示所有管道应用后的项目数。通过组合ngFor提供的索引和最后一个值,我发现了另一个解决方案:

<div *ngFor="#item of (items | filter); #i = index; #last = last">
...
  <div id="counter_id" *ngIf="last">{{index + 1}} results</div>
</div>

答案 3 :(得分:6)

我找到了最简单的解决方案:

  1. 在您的组件中:添加一个包含当前计数的字段
  2.   filterMetadata = { count: 0 };
    
    1. 在您的模板中:将filterMetadata作为参数添加到过滤器管道
    2.   <tr *ngFor="#d of data.results | filter:filterText:filterMetadata | pagination:resultsPerPage:currentPage">
      
      1. 将filterMetadata.count插入到显示所显示记录数的元素中。
      2.   <span> {{filterMetadata.count}} records displayed</span>
        
        1. 在过滤器管道中,完成过滤后更新filterMetadata.count字段
        2.   transform(items, ..., filterMetadata) {
              // filtering
              let filteredItems = filter(items);
          
              filterMetadata.count = filteredItems.length;
              return filteredItems;
            }
          

          此解决方案仍使用纯管道,因此不会出现性能下降。 如果您有多个管道进行过滤,则应将filterMetadata作为参数添加到所有管道,因为一旦管道返回空数组,角度就会停止调用管道序列,因此您无法将其添加到第一个或最后一个过滤管。

答案 4 :(得分:5)

我遇到了同样的问题,虽然@bixelbits的回答得到了批准,但我觉得它并不理想,特别适用于大数据。

不是在每个元素中返回原始数组,我认为最好避免Pipes这个问题,至少在当前的Angular 2实现(rc4)中。

更好的解决方案是使用普通组件的功能来过滤数据,如下所示:

// mycomponent.component.ts  
filter() {
  let arr = this.data.filter(
      // just an example
      item => item.toLowerCase().includes(
        // term is a local variable I get it's from <input> 
        this.term.toLowerCase()
      )
    );
  this.filteredLength = arr.length;
  return arr;
}

然后,在模板中:

<ul>
  <li *ngFor="let el of filter()"> 
    {{ el | json }}
  </li>
</ul>
// mycomponent.component.html
<p > There are {{ filteredLength }} element(s) in this page</p>

除非您真的想使用Pipes,否则我建议您在上述示例中避免使用它们。

答案 5 :(得分:4)

所以我找到了解决方法。

我创建了一个管道,它接受一个对象引用并使用当前通过管道的计数更新一个属性。

@Pipe({
    name: 'count'
})

export class CountPipe implements PipeTransform {
    transform(value, args) {
        if (!args) {
            return value;
        }else if (typeof args === "object"){

            //Update specified object key with count being passed through
            args.object[args.key] = value.length;

            return value;

        }else{
            return value;
        }
    }
}

然后在你的视图中链接一个像这样的分页组件。

pagination-controls(#controls="", [items]="items.length", (onChange)="o") 

tbody
    tr(*ngFor=`let item of items
        | filter_pipe: { .... }
        | count: { object: controls , key: 'items' }
        | pagination_pipe: { ... } `)

一旦将count属性从管道中提取到当前组件或子组件,您就可以对它执行任何操作。

答案 6 :(得分:0)

在我的情况下,我需要运行已过滤的元素并运行一些分析。

我的解决方案是简单地传递一个函数并在最后一个管道上返回数组。您也可以为此创建一个管道,但我已将其添加到过滤器中的最后一个管道:

HTML

<divclass="card" *ngFor="let job of jobs | employee:jobFilter.selectedEmployee | managerStatus:jobFilter.selectedStatus | dateOrder:jobFilter"> 

组件

this.jobFilter = {
  jobStatuses: {},  // status labels
  ordering: 'asc',
  selectedEmployee: {},
  selectedStatus: {}, // results status
  fn: this.parseFilteredArr
};

parseFilteredArr(arr) {
  console.log(arr);
}

import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
  name: 'dateOrder'
})
export class DateOrderPipe implements PipeTransform {
 transform(value: any, args?: any): any {
   const arr = Array.isArray(value)
    ? value.reverse()
    : value;
  args.fn(arr);
  return arr;
}
}

如您所见,我已在管道中调用该功能

  

args.fn(ARR);

现在可以在控制器中处理它。

答案 7 :(得分:0)

假设您的ngFor看起来像:

<div #cardHolder>
    <app-card *ngFor="let card of cards|pipeA:paramX|pipeB:paramY"></app-card>
</div>

然后,您可以在组件中使用类似以下内容的

 get displayedCards() : number {
    let ch = this.cardHolder.nativeElement;

    // In case cardHolder has not been rendered yet...
    if(!ch)
      return 0;

    return ch.children.length;

  }

您可以通过简单的插值在视图中显示

{{displayedCards}}

优点包括不需要修改管道以返回其他数据。

答案 8 :(得分:0)

  1. 对我有用的是:

    • 不要使用管道,几个月后,您将无法说出它们的含义,也无法弄清奇怪的语法。

    • 框架(这里为Angular)是可以的,但在一定程度上,请保持模板简单ngFor绑定到数据数组。超出此范围意味着您将纠结于特定于框架的特殊语法和(不断变化的)机制。 (这说明了为什么我们有此帖子/问题首先不应该存在)

    • HTML模板用于布局,请保持原样。所有逻辑,数据过滤等都应保留在代码中,并放在简单的类中。

  2. 只需在组件或服务中创建一个筛选器方法,然后调用它来筛选您的数据。

  3. 在组件/服务上暴露一个.Count道具,以显示实际的过滤数据动态计数(即通常为.length)。