CuriousG
CuriousG

Reputation: 97

Count of filtered ngfor angular

Is there an easier way to get the count of actual displayed results in an ngFor that has a nested ngIf without?

<div *ngFor="let stuff of things">
   <ng-container *ngIf="stuff.key === 'value'">
     **I'd like an easier way to get the result of this *ngIf .length and use it elsewhere**
   </ng-container>
</div>

I tried to use @ViewChildren and hoped for;

@ViewChildren('myContainerRef') containerRef: QueryList<any>

<label>Count {{ myContainerRef.length }}</label>
<div #myRef *ngFor="let stuff of things">
</div>

but get undefined result. Is my last resort doing a filter on the incoming array to get the count and assign it public vars? Or is there an easier way to get the count of an ngfor results that match a condition / are displayed?

Upvotes: 2

Views: 1159

Answers (3)

Igor Motovilov
Igor Motovilov

Reputation: 159

You can create pipe like this

@Pipe({
  name: 'filterThings',
})
export class FilterThingsPipe implements PipeTransform {

  transform(array: Thing[], value: string): Thing[] {
    return array.filter(item => item.key == value);
  }

}

then use it inside template

<div *ngFor="let stuff of things | filterThings:'val1'; let length = count">
  {{stuff.key}} of {{length}}
</div>

Pipe will return filtered array, and as ngFor provides count as one of it's exported values docs here you can assign in to template variable (length = count) inside ngFor expression

Upvotes: -1

Joosep Parts
Joosep Parts

Reputation: 6235

You can use ViewChildren in AfterViewInit at the earliest. You can search for ng-container but would be better to search the elements you're after with #myRef so it would count only the ones you are interested in.

<div *ngFor="let stuff of things">
  <ng-container #myRef>
    {{ stuff }} **I'd like an easier way to get the result of this *ngIf .length
    and use it elsewhere**
  </ng-container>
</div>
<br />
TotalContainers: {{ containersCount }}
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent implements AfterContentChecked {
  @ViewChildren('myRef') containers: QueryList<ElementRef>;

  things = Array.from(Array(10).keys());
  containersCount: number;

  constructor() {}

  ngAfterContentChecked() {
    this.containersCount = this.containers?.length;
  }
}

Working example: https://stackblitz.com/edit/angular-ivy-vpq5n4?file=src%2Fapp%2Fapp.component.ts

Upvotes: 1

gavgrif
gavgrif

Reputation: 15509

I would change the logic to allow the filtering to occur in the .ts file and then you have both the iterable and the count...

The following allows the filtering of the original array and the length is the number of matching items

.component.ts
   const filteredThings= things.filter(x => x.key === 'value');

.component.html
   <div *ngFor="let thing of filteredThings">
      {{ thing.xyz }} {{filteredThings.length}}
   </div>

Upvotes: 2

Related Questions