简体   繁体   English

如何在 *ngfor 中计算 *ngif

[英]how to count *ngif inside *ngfor

I want to know how many items are displayed in following piece of code.我想知道在下面的一段代码中显示了多少项目。

component.html:组件.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:组件.ts:

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

  constructor() { }

  protected counter: number = 0;
}

items (json presentation):项目(json 表示):

[
    {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.注意 1:在上面的示例数据中,只有数组中对象的count属性可以随时由应用程序的任何其他组件更改。

Note 2: Actually, items is an array of arrays, but for better representation and better understanding I changed it to array of objects here.注2:实际上, items是一个arrays的数组,但是为了更好的表达和更好的理解,我在这里把它改成了array of objects。


I tried to count HTML nodes but this error happens:我试图计算 HTML 个节点,但发生此错误:

NG0100: ExpressionChangedAfterItHasBeenCheckedError

I also tried *ngIf="addCounter(item.count < 100)" but addCounter() is triggered on every event on page (scroll events, etc).我也试过 *ngIf="addCounter(item.count < 100)" 但 addCounter() 在页面上的每个事件(滚动事件等)上触发。

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).我也无法过滤 ts 文件中的items (有很多 ngfors 并且items不断更新,因此 ts 文件变得太复杂,因为只有一个简单的计数器)。

Is there a better approach out there?有更好的方法吗?

You should do all data filtering, processing, and preparation in the component class. The template should be used for displaying data only.所有的数据过滤、处理、准备工作都应该在class这个组件中进行。该模板应该只用于展示数据。 This is some approach to display the items according to the conditions mentioned in the question:这是根据问题中提到的条件显示项目的一些方法:

component.ts组件.ts

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

template.html模板.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>

As per the comments, you can add a counter in the TS file add a method to increment every time item.counter < 100 ;根据评论,您可以在 TS 文件中添加一个计数器,添加一个每次递增的方法item.counter < 100

Updated Answer based on the comment and extra information provided in the question.根据问题中提供的评论和额外信息更新了答案

You can use set property on input .您可以在input上使用set属性。 Create two variables: counter (already there) and itemList in the ts file:在ts文件中创建两个变量: counter (已经存在)和itemList

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.注2:实际上,items是一个arrays的数组,但是为了更好的表达和更好的理解,我在这里把它改成了array of objects。

You can use flatMap in the filter to get only the list of object just for counting purpose.您可以在过滤器中使用 flatMap 仅获取 object 的列表以用于计数目的。

I'd do something like this: Create the interface for the JSON我会做这样的事情:为 JSON 创建接口

export interface ListItem {
  id: number;
  count: number;
  title: string;
}

And use it in your component.ts:并在你的 component.ts 中使用它:

@Component({selector: 'app-list', changeDetection: ChangeDetection.OnPush})
export class ListComponent {
  @Input() items?: ListItem [] | null; // with ? and | null your component will work with async pipe and strict TypeScript
}

Your ListComponent html:你的ListComponent html:

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

<ol> // It's always better to use native html element.
  <li *ngFor="let item of items">{{item.title}}</li>
</ol>

Create an Angular pipe that does all the logic:创建一个执行所有逻辑的Angular pipe

@Pipe({name: 'countFilter'})
export class CountFilterPipe implements PipeTransform{
  transform(value: ListItem[] | null | undefined) { // with the above logic mark null | undefined too.
    if(!value) {
      return;
    }
    return value.filter(item => item => item.count < 100);
  }
}

Your AppComponent or any component html where you use app-list :您的AppComponent或您使用app-list任何组件 html :

<app-list [items]="items | countFilter"></app-list>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM