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

问题描述 投票:21回答:7

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

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

页面上还有另一个元素显示显示的记录数。这些元素最初绑定到data.Results的长度。

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

angular angular2-directives
7个回答
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>

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

7
投票

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

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

6
投票

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

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

    filterMetadata.count = filteredItems.length;
    return filteredItems;
  }

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


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,否则我会建议你在上面的例子中避免使用它们。


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属性从管道中提取到当前组件或子组件,您就可以对其执行任何操作。


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

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

© www.soinside.com 2019 - 2024. All rights reserved.