2

I want to know how many items are displayed in following piece of code.

component.html:

<p *ngIf="counter">{{counter}} items displayed!</p>
<p *ngIf="!counter">Nothing to display!</p>

<ng-container *ngFor="let item of items">
  <li *ngIf="item.count < 100">{{counter}}. {{item.title}}</li>
</ng-container>

component.ts:

export class ListComponent {
  @Input('items') items: any[];

  constructor() { }

  protected counter: number = 0;
}

items (json presentation):

[
    {id: 1, count: 100, title: "title #1"},
    {id: 2, count: 20, title: "title #2"},
    {id: 3, count: 0, title: "title #3"},
    {id: 4, count: 200, title: "title #4"},
    {id: 5, count: 100, title: "title #5"},
]

Note 1: In above sample data, only count property of objects in the array can change at any moment of time, by any other component of the app.

Note 2: Actually, items is an array of arrays, but for better representation and better understanding I changed it to array of objects here.


I tried to count HTML nodes but this error happens:

NG0100: ExpressionChangedAfterItHasBeenCheckedError

I also tried *ngIf="addCounter(item.count < 100)" but addCounter() is triggered on every event on page (scroll events, etc).

I also can not filter items in the ts file (there are lots of ngfors and the items is constantly updated, so the ts file gets too complicated because of just a simple counter).

Is there a better approach out there?

velediqa
  • 53
  • 7

3 Answers3

1

You should do all data filtering, processing, and preparation in the component class. The template should be used for displaying data only. This is some approach to display the items according to the conditions mentioned in the question:

component.ts

filteredItems = items.filter(item => item.count < 100);
counter = filteredItems.length;

template.html

<p *ngIf="counter">{{counter}} items displayed!</p>
<p *ngIf="!counter">Nothing to display!</p>

<ng-container *ngFor="let item of filteredItems; let i = index">
  <li>{{i}}. {{item.title}}</li>
</ng-container>
Apoorva Chikara
  • 8,277
  • 3
  • 20
  • 35
Rami Assi
  • 910
  • 2
  • 10
  • 19
  • Thank you, but `items` is sent to the component via @Input(). Where should I put the filter line? And also how can I update it when `items` is changed? – velediqa Sep 08 '21 at 05:51
  • No problem at all you can detect @Input changes using [`ngOnChanges`](https://stackoverflow.com/a/44686085/7149235) – Rami Assi Sep 08 '21 at 06:05
  • It seems like ngOnChanges() doesn't detect changes of inner items, e.g. `items[index].count`. Probably only detects changes to `items` itself?! (in my app, `count` property of objects in `items` array is updated but total number of objects in `items` array is not changed at all). – velediqa Sep 08 '21 at 06:24
  • You can use set property on input to make the changes by creating a filter. – Apoorva Chikara Sep 08 '21 at 15:33
0

As per the comments, you can add a counter in the TS file add a method to increment every time item.counter < 100;

Updated Answer based on the comment and extra information provided in the question.

You can use set property on input. Create two variables: counter(already there) and itemList in the ts file :

export class ListComponent {
  protected counter: number = 0;
  public itemList: Array<any>= [];
  @Input('items') set item (value) {
      console.log(value) // now you get items here
      this.itemList = value;
      this.filterBasedOnCount(value);
  }

  constructor() { }
  
  filterBasedOnCount(items) {
     this.counter =  items.filter(item => item.count < 100).length;
  }
  
}

Note 2: Actually, items is an array of arrays, but for better representation and better understanding I changed it to array of objects here.

You can use flatMap in the filter to get only the list of object just for counting purpose.

Apoorva Chikara
  • 8,277
  • 3
  • 20
  • 35
  • I want to show all items where items.count < 100 (or any other condition), and I want to show how many items are displayed. I'm not looking for pagination, but to count how many times *ngif is true (how many
  • is displayed). Thank you, but a simple *ngfor index is not what i'm looking for.
  • – velediqa Sep 08 '21 at 05:32
  • Update the answer please check this if it helps. – Apoorva Chikara Sep 08 '21 at 05:52
  • I already tried this (as I mentioned in my question before). Now countItem() is triggered on every event, e.g. with page scroll. If there are 10 items to display, it goes up and up with scrolling the page. also NG0100: ExpressionChangedAfterItHasBeenCheckedError is thrown on every trigger. – velediqa Sep 08 '21 at 06:08
  • Is It possible for you to add the whole code because it is difficult to give in depth answer with this piece. – Apoorva Chikara Sep 08 '21 at 06:11
  • Updated the answer, you can check now. – Apoorva Chikara Sep 08 '21 at 16:11