2

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?

CuriousG
  • 97
  • 6
  • Did you check https://stackoverflow.com/a/57726154/2490286 – misha130 Apr 26 '22 at 00:21
  • Why don;t you just use another variable on ts side and have a filteredArray and then you can use filteredArray.length anywhere you want and you don't need an *ngIf in your template. – user1779362 Apr 26 '22 at 01:20

3 Answers3

2

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>
gavgrif
  • 15,194
  • 2
  • 25
  • 27
1

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

Joosep Parts
  • 5,372
  • 2
  • 8
  • 33
-1

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

  • Your answer could be improved by adding more information on what the code does and how it helps the OP. – Tyler2P Apr 26 '22 at 17:09