如何在视图中仅循环一次对象(单个 *ngFor)?

How to loop through an object only once in the view (single *ngFor)?

我有这个对象,每个 属性 都有一个数组作为它的值。我只想循环一次这个对象而不是使用 2 *ngFor 指令,因为它会导致我的应用程序运行缓慢。我也愿意从此对象创建一个数组,但我仍然想为每个部分添加一个部分 ID,如下例所示。谁能指出我正确的方向?非常感谢!这是我的代码。

LIVE DEMO

<div *ngFor="let group of dataObject | keyvalue">
    {{group.key}}
    <div *ngFor="let item of group.value; let i=index;">
        {{item.name}}
    </div>
</div>

注意:我的最终目标是将每个人包装到他们所属的部分,并为每个部分添加一个 id。 示例:

  <div id = "parentId"> 
     <div id = "section-a">
        list of all users that belong in section a
     </div>
     <div id = "section-b">
         list of all users that belong in section b
     </div>
     <div id = "section-c">
         list of all users that belong in section c
     </div>
 
    <div>
    ......
    ......
  </div>

无法使用 *ngFor 执行此操作。您可以在组件中准备一个平面版本的数据,并提供一个深度为 1 的数组以仅循环一次。

示例 AppComponent:

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

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html"
})
export class AppComponent {
  
  dataObject = {
    A: [
      { id: 1, name: "Mike", lastname: "asmith" },
      { id: 2, name: "Mary", lastname: "alters" },
      { id: 3, name: "Boris", lastname: "al" }
    ],
    B: [
      { id: 1, name: "Mike", lastname: "bmith" },
      { id: 2, name: "Mary", lastname: "balters" },
      { id: 3, name: "Boris", lastname: "bl" }
    ],
    C: [
      { id: 1, name: "Mike", lastname: "cmith" },
      { id: 2, name: "Mary", lastname: "calters" },
      { id: 3, name: "Boris", lastname: "dl" }
    ],
    D: [
      { id: 1, name: "Mike", lastname: "dmith" },
      { id: 2, name: "Mary", lastname: "dalters" },
      { id: 3, name: "Boris", lastname: "dl" }
    ],
    E: [
      { id: 1, name: "Mike", lastname: "emith" },
      { id: 2, name: "Mary", lastname: "ealters" },
      { id: 3, name: "Boris", lastname: "el" }
    ]
  };

  flatDataObject = [];

  constructor() {
    // Loop through dataObject
    Object.keys(this.dataObject).forEach(k => {
      // Assign key as a `key` attribute to first object in array.
      this.dataObject[k][0].key = k;
      // Push the arrays into one
      this.flatDataObject.push(...this.dataObject[k]);
    });
  }
}

示例HTML:

<div *ngFor="let group of flatDataObject">
  <!-- Check if the object has `key` attribute -->
  <div *ngIf="group.key">
    <!-- If it has `key` attribute: -->
    {{group.key}}
  </div>
  <div>
    {{group.lastname}}
  </div>
</div>

这是演示:https://stackblitz.com/edit/angular-6-template-sk8tkm?file=src/app/app.component.html

这是我能想到的最好的解决方案。它仍然总共有两个循环,但至少其中一个没有使用 *ngFor.

你有一个 Dictionary of Arrays(作为数据结构),所以你有以下必要迭代的时间复杂度:

  • O(n) : n代表字典[=45]的长度 =]
  • O(m) : m代表长度(类型Array

您执行迭代的总复杂度为 O(mn)O(m*n) 任何地方。例如下面的代码具有相同的时间复杂度:

Object.entries(this.dataObject).reduce((result, entry) => {
    const [key, value] = entry;
    value.forEach((v, i) => (result[`${key}_${i}`] = v.name));
    return result;
},{});

如果你有限制,我认为你可以减少 借助语言方法和像下面这样的方便技巧的时间复杂度:

Object.values(this.dataObject).map(m => m).flat().map(m => m.name);

然后,拆分每 3 个项目:

<div *ngFor="let item of simplified2; let i = index" [id]="findId(i)">
  {{findId(i)}} {{item}}
</div>


findId(index: number) {
    return Math.floor(index / 3); //if you are sure about the length of values
}

我在 stackblitz. You can study more about Data Structures in JavaScript: Arrays, HashMaps, and Lists

中提供了上述所有内容

您可以生成一个新的 属性 reduced 并使用这个新的 属性

在你的组件中

dataObject = {
    A: [
        {id: 1, name: 'Mike', lastname: 'asmith'},
        {id: 2, name: 'Mary', lastname: 'alters'},
        {id: 3, name: 'Boris', lastname: 'al'}
    ],
    B: [
        {id: 1, name: 'Lauren', lastname: 'bmith'},
        {id: 2, name: 'Travis', lastname: 'balters'},
        {id: 3, name: 'Barn', lastname: 'bl'}
    ], 
    ...
}
dataObjectDisp = Object.entries(this.dataObject).reduce((prev, [key, value]) =>{
  return [...prev, ...value.map((user, index) => ({ 
    ...user, parent: key, index }))]
}, [])

以上代码会将结构缩减为

[
  {
    "id": 1,
    "name": "Mike",
    "lastname": "asmith",
    "parent": "A",
    "index": 0
  },
  {
    "id": 2,
    "name": "Mary",
    "lastname": "alters",
    "parent": "A",
    "index": 1
  },
  ...
]

现在我们有办法确定新部分何时开始。它的索引将为零

要显示 html 您可以执行如下操作

<h1>New</h1>
<div *ngFor="let item of dataObjectDisp; let i = index" [attr.data-article]='"section" + item.parent'>
  <ng-container *ngIf="item.index === 0">
    {{ item.parent }}
  </ng-container>
  <div>
    {{item.lastname}}
  </div>
</div>

注意属性 [attr.data-article]='"section" + item.parent'。这可以用来识别不同的部分