我有一个ngFor在表中创建行,过滤和分页。
<tr *ngFor="#d of data.results | filter:filterText | pagination:resultsPerPage:currentPage">
页面上还有另一个元素显示显示的记录数。这些元素最初绑定到data.Results的长度。
如何获取应用过滤器管道后显示的数据长度,以便我可以正确显示它。 ngFor中提供的局部变量都没有考虑到这一点。
您可以通过在管道中转换数组来获取项目的计数。
我们的想法是管道将数组转换为另一个数组,其中每个元素都有一个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>
一种方法是使用@ViewChildren()
的模板变量
<tr #myVar *ngFor="let d of data.results | filter:filterText | pagination:resultsPerPage:currentPage">
@ViewChildren('myVar') createdItems;
ngAfterViewInit() {
console.log(this.createdItems.toArray().length);
}
这不是原始问题的目的,但我也在寻找一种方法来显示所有管道应用后的项目数。通过组合ngFor提供的索引和最后一个值,我找到了另一个解决方案:
<div *ngFor="#item of (items | filter); #i = index; #last = last">
...
<div id="counter_id" *ngIf="last">{{index + 1}} results</div>
</div>
我找到了最简单的解决方案如下:
filterMetadata = { count: 0 };
<tr *ngFor="#d of data.results | filter:filterText:filterMetadata | pagination:resultsPerPage:currentPage">
<span> {{filterMetadata.count}} records displayed</span>
transform(items, ..., filterMetadata) {
// filtering
let filteredItems = filter(items);
filterMetadata.count = filteredItems.length;
return filteredItems;
}
该解决方案仍然使用纯管道,因此没有性能下降。如果您有多个管道进行过滤,则应将filterMetadata作为参数添加到所有管道,因为一旦管道返回空数组,角度就会停止调用管道序列,因此您不能只将其添加到第一个或最后过滤管道。
我遇到了同样的问题,虽然@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
,否则我会建议你在上面的例子中避免使用它们。
所以我找到了解决方法。
我创建了一个管道,它接受一个对象引用并使用当前通过管道的计数更新一个属性。
@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属性从管道中提取到当前组件或子组件,您就可以对其执行任何操作。
在我的情况下,我需要运行过滤后的元素并运行一些分析。
我的解决方案是简单地传递一个函数并在最后一个管道上返回数组。您也可以为此创建一个管道,但我已将其添加到过滤器中的最后一个管道:
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);
现在可以在控制器中处理它。