Avatar ·

Как получить ключ и значение объекта при использовании *ngFor в Angular?

Всем привет! Я новичок в Angular и TypeScript, и у меня возникла проблема при выводе данных из объекта через *ngFor. У меня есть объект с данными о пользователях, где ключи — это ID пользователей, а значения — объекты с их информацией: ```typescript users = { 1: { name: 'Иван', age: 25 }, 2: { name: 'Мария', age: 30 }, 3: { name: 'Петр', age: 28 } }; ``` Когда я пытаюсь вывести это в шаблоне с помощью *ngFor, я не понимаю, как получить и ключ, и значение одновременно. Обычный *ngFor для массивов работает просто: `let item of items`, но для объектов так не получается. Я пробовал писать так: ```html

{{ user.name }}

``` Но Angular выдает ошибку, что нельзя итерировать объект. Я читал, что можно использовать `Object.keys()`, но не понимаю, как это применить в шаблоне. Подскажите, пожалуйста, как правильно вывести и ключ (ID), и значение (объект с данными) в *ngFor? Нужен простой и понятный пример для начинающих. Заранее спасибо за помощь! <<>>

Использование KeyValuePipe для итерации по объектам

В Angular есть встроенный пайп KeyValuePipe, который специально создан для решения этой задачи. Он преобразует объект в массив пар ключ-значение, которые можно легко итерировать с помощью *ngFor.

Вот как это работает на практике:

// В вашем компоненте (TypeScript)
import { Component } from '@angular/core';

@Component({
  selector: 'app-user-list',
  template: `
    <div *ngFor="let userEntry of users | keyvalue">
      <p>ID пользователя: {{ userEntry.key }}</p>
      <p>Имя: {{ userEntry.value.name }}</p>
      <p>Возраст: {{ userEntry.value.age }}</p>
      <hr>
    </div>
  `
})
export class UserListComponent {
  users = {
    1: { name: 'Иван', age: 25 },
    2: { name: 'Мария', age: 30 },
    3: { name: 'Петр', age: 28 }
  };
}

Как это работает?

  • KeyValuePipe берет объект и преобразует его в массив объектов с двумя свойствами: key и value.
  • userEntry.key — это ключ исходного объекта (в нашем случае ID пользователя: 1, 2, 3).
  • userEntry.value — это значение исходного объекта (объект с name и age).

Важные моменты

  • Порядок элементов: KeyValuePipe сохраняет порядок, в котором ключи были добавлены в объект (в соответствии со спецификацией ES2015).
  • Производительность: Этот пайп создает новый массив при каждом цикле обнаружения изменений, что может влиять на производительность при очень больших объектах. В таких случаях лучше преобразовывать объект в массив прямо в компоненте.
  • Сортировка: По умолчанию ключи сортируются по возрастанию. Если вам нужен оригинальный порядок, используйте keyvalue: 'noSort':
<div *ngFor="let userEntry of users | keyvalue: 'noSort'">
  <p>{{ userEntry.key }}: {{ userEntry.value.name }}</p>
</div>

Альтернативный подход — преобразование в компоненте

Если вы предпочитаете управлять данными в коде компонента (например, для дополнительной обработки), можно преобразовать объект в массив вручную:

// В компоненте
import { Component } from '@angular/core';

@Component({
  selector: 'app-user-list',
  template: `
    <div *ngFor="let user of userArray">
      <p>ID: {{ user.id }}, Имя: {{ user.data.name }}</p>
    </div>
  `
})
export class UserListComponent {
  users = {
    1: { name: 'Иван', age: 25 },
    2: { name: 'Мария', age: 30 },
    3: { name: 'Петр', age: 28 }
  };

  userArray: { id: number; data: { name: string; age: number } }[] = [];

  ngOnInit() {
    this.userArray = Object.entries(this.users).map(([id, data]) => ({
      id: Number(id),
      data
    }));
  }
}

Этот подход дает больше контроля и может быть полезен, если вам нужно выполнить дополнительные преобразования или фильтрацию данных перед отображением.

Рекомендую использовать KeyValuePipe для простых случаев и преобразование в компоненте — для более сложной логики.

<<>>

Использование Object.keys() в шаблоне

Если вы не хотите использовать пайпы или преобразования в компоненте, можно применить Object.keys() прямо в шаблоне. Это более громоздкий способ, но он работает и помогает понять механику:

<div *ngFor="let key of objectKeys(users)">
  <p>Ключ: {{ key }}</p>
  <p>Имя: {{ users[key].name }}</p>
  <p>Возраст: {{ users[key].age }}</p>
</div>

Для этого в компоненте нужно определить метод objectKeys():

export class UserListComponent {
  users = {
    1: { name: 'Иван', age: 25 },
    2: { name: 'Мария', age: 30 }
  };

  objectKeys(obj: any): string[] {
    return Object.keys(obj);
  }
}

Недостатки этого подхода:

  • Метод вызывается при каждой проверке изменений, что может снизить производительность.
  • Код в шаблоне выглядит менее чисто по сравнению с KeyValuePipe.
  • Типизация страдает, так как Object.keys() возвращает string[].

Этот способ подходит для быстрых прототипов или обучения, но в продакшене лучше использовать KeyValuePipe или преобразование массива в компоненте.