Как найти количество элементов в ngFor после применения труб

У меня есть ngДля создания строк в таблице, которая отфильтрована и выгружена.

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

На странице отображается еще один элемент, отображающий количество отображаемых записей. Эти элементы первоначально привязаны к данным. Длина результатов.

Как получить длину данных, которые будут отображаться после применения фильтра, чтобы я мог отображать его правильно. Ни одна из предоставленных локальных переменных в ngFor, похоже, не учитывает это.

Ответ 1

Вы можете получить количество элементов, преобразуя массив в канал.

Идея состоит в том, что труба преобразует массив в другой массив, где каждый элемент имеет свойство элемента, а родительское свойство представляет отфильтрованный (или оригинальный) массив:

@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

Один из способов - использовать переменные шаблона с @ViewChildren()

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

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

Ответ 3

Это не совсем цель исходного вопроса, но я также искал способ отображения количества элементов, когда все трубы были применены. Объединив индекс и последние значения, предоставленные ngFor, я нашел это другое решение:

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

Ответ 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 извлекается из канала либо к текущему компоненту, либо к дочернему компоненту, вы можете что-то с ним делать.

Ответ 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 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, я бы рекомендовал вам избегать их в ситуациях, подобных приведенному выше примеру.

Ответ 6

В моем случае мне нужно было пройти через отфильтрованные элементы и выполнить некоторый анализ.

Мои решения - просто передать функцию и вернуть массив на последнем канале. Вы могли бы просто создать канал специально для этого, но я добавил его в свой последний канал в фильтрах:

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(обр);

и теперь может обрабатывать его в контроллере.