Angular 7使用*ngfor分组数据

4

目前我的Angular应用程序中有这样的数据输入

https://stackblitz.com/edit/angular-ymmt4d

enter image description here

如何按州和县分组和排序数据,并像下表一样显示?

enter image description here

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  data = [
    { state: 'MN', county: '1', item: 0.297 },
    { state: 'MN', county: '1', item: 0.04 },
      { state: 'CA', county: '2', item: 0.019 },
    { state: 'MN', county: '1', item: 0.0374 }, 
    { state: 'CA', county: '2', item: 0.037 }
]
}
 <table >
        <tr>
          <th>State</th>
          <th>County</th>
          <th>Item</th>
        </tr>
        <ng-container *ngFor="let dataitem of data">
        <tr>
          <td>{{dataitem.state}}</td>
          <td>{{dataitem.county}}</td>
          <td>{{dataitem.item}}</td>
        </tr>
        </ng-container>
    </table>


你是否能将数据格式更改为类似于 {state:'MN', county:'1',item;[0.297,0.04,0.0374]}? - Observablerxjs
我认为我无法更改数据格式。 - Pein
4
这篇博客介绍了如何在Angular 4中创建一个自定义管道来实现分组功能。通过该管道,用户可以对数组进行分组,并按照指定的属性进行排序。文章详细介绍了管道代码的实现过程和使用方法,同时提供了代码示例以及相关说明。 - Gaspar
5个回答

3
如果数据已经排序,您可以使用let i = index,并使用条件运算符检查前一个数据是否相等。
<ng-container *ngFor="let dataitem of data;let i=index">
<tr>
  <td>{{i>0 && data[i-1].state==dataitem.state?'':dataitem.state}}</td>
  <td>{{i>0 && data[i-1].county==dataitem.county?'':dataitem.county}}</td>
  <td>{{dataitem.item}}</td>
</tr>
</ng-container>

2
将您的数据使用lodash转换为多个数组。

https://lodash.com/docs/4.17.11#groupBy

注: "Original Answer" 翻译成中文是 "最初的回答"。
import { groupBy } from 'lodash-es'
const states = groupBy(data, 'state')


你的表格中可以有多个tbody。最初的回答是:

在你的表格中,可以有多个tbody。

<tbody *ngFor="let state of states">...</tbody>

1
使用this answer作为指南,您可以提前整理数据(或使用管道)来创建嵌套对象。
大致类似于以下内容(从链接示例中粗略提取)
key = 'state';
data = data.reduce((data, x) => {
    (data[x[key]] = data[x[key]] || []).push(x);
    return data;
  }, {});

应该生成类似于以下内容的东西。
data = [
    { 'MN': [
        { county: '1', item: 0.297 }
        ....
    ]}
]

或者,如果您的列表已经排序,您可以使用复杂的 *ngIf 和索引逻辑。在这里阅读更多。类似于以下内容:

<div *ngFor="let item of list; let i = index;">
  <div *ngIf="i > 0 && item.state !== list[i-1].state">{{item.state}}</div>
</div>

1
这是一个完全可行的解决方案,带有Stackblitz演示链接,可以合并相似的单元格。
您需要为每个项目计算一次“rowspan”,并将其绑定到“td”的“rowspan”属性上。您还必须有条件地呈现“td”,仅在每个州的第一个项目中显示它。
为此,您可以创建一个预处理数组,按状态和县排序,并添加了状态和县的“span”属性。
要设置“span”属性,您可以通过过滤原始数组来计算每个州和州的子级数量。
目标是获得像这样的数组:
[
  {state: "CA", county: "2", item: 0.019, stateSpan: 3, countySpan: 2},
  {state: "CA", county: "2", item: 0.037, stateSpan: 0, countySpan: 0},
  {state: "CA", county: "3", item: 0.14, stateSpan: 0, countySpan: 1},
  {state: "MN", county: "1", item: 0.297, stateSpan: 4, countySpan: 3},
  {state: "MN", county: "1", item: 0.04, stateSpan: 0, countySpan: 0},
  {state: "MN", county: "1", item: 0.0374, stateSpan: 0, countySpan: 0},
  {state: "MN", county: "3", item: 0.14, stateSpan: 0, countySpan: 1}
]

这是代码:

 <table>
    <tr>
      <th>State</th>
      <th>County</th>
      <th>Item</th>
    </tr>
    <tr *ngFor="let item of dataExt">
      <td [attr.rowspan]="item.stateSpan" *ngIf="item.stateSpan">{{ item.state }}</td>
      <td [attr.rowspan]="item.countySpan" *ngIf="item.countySpan">{{ item.county }}</td>
      <td>{{ item.item }}</td>
    </tr>
</table>

export class AppComponent  {
  data = [
    { state: 'MN', county: '1', item: 0.297 },
    { state: 'MN', county: '1', item: 0.04 },
    { state: 'MN', county: '3', item: 0.14 },
    { state: 'CA', county: '2', item: 0.019 },
    { state: 'MN', county: '1', item: 0.0374 }, 
    { state: 'CA', county: '2', item: 0.037 },
    { state: 'CA', county: '3', item: 0.14 }
  ];

  dataExt: any[] = [];

  constructor() {
    this.processData();
  }

  private processData() {
    const statesSeen = {};
    const countiesSeen = {};

    this.dataExt = this.data.sort((a, b) => {
      const stateComp = a.state.localeCompare(b.state);
      return stateComp ? stateComp : a.county.localeCompare(b.county);
    }).map(x => {
      const stateSpan = statesSeen[x.state] ? 0 :
        this.data.filter(y => y.state === x.state).length;

      statesSeen[x.state] = true;

      const countySpan = countiesSeen[x.state] && countiesSeen[x.state][x.county] ? 0 :
        this.data.filter(y => y.state === x.state && y.county === x.county).length;

      countiesSeen[x.state] = countiesSeen[x.state] || {};
      countiesSeen[x.state][x.county] = true;

      return { ...x, stateSpan, countySpan };
    });
  }
}

这是生成的表格:

enter image description here


0

也许是这样的:

interface Item {
  state?: string;
  county?: string;
  item: number;
}

private processData(data: any[]): Item[] {
  // Sort alphabetically
  const sorted = data.sort((a, b) => {
    if(a.state < b.state) { return -1; }
    if(a.state > b.state) { return 1; }
    return 0;
  });

  // Return original object if state value is different to
  // previous object (or if first iteration). Otherwise
  // return object with sole `item` property.
  return sorted.map((el, i) => {
    if (i === 0 || sorted[i-1].state !== el.state) {
      return el;
    } else {
      return {
        item: el.item
      };
    }
  });
}

这应该是 O(log n) 复杂度,结果将会像这样:

[
  { state: 'CA', county: '2', item: 0.019 },
  { item: 0.037 },
  { state: 'MN', county: '1', item: 0.297 },
  ...
]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接