Avatar ·

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

Привет! Я новичок в Angular и TypeScript, и у меня возникла проблема при работе с объектами в шаблоне. У меня есть объект с данными пользователей: ```typescript interface Users { [key: string]: { name: string; age: number }; } const users: Users = { user1: { name: 'Иван', age: 30 }, user2: { name: 'Мария', age: 25 }, user3: { name: 'Петр', age: 35 } }; ``` Я пытаюсь вывести эти данные в шаблоне с помощью *ngFor, но не могу понять, как получить и ключ (user1, user2), и значение (объект с name и age). Если я делаю просто: ```html
{{ user }}
``` То Angular выдает ошибку, потому что *ngFor работает только с массивами. Я пробовал использовать Object.keys(), но не знаю, как правильно это применить в шаблоне. Подскажите, как правильно перебрать объект и получить доступ к ключам и значениям одновременно? Желательно с примерами кода, чтобы было понятно новичку. Спасибо! <<>>

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

В Angular есть встроенный пайп KeyValuePipe, который преобразует объект в массив пар ключ-значение. Это самое простое и правильное решение для вашей задачи.

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

interface User {
  name: string;
  age: number;
}

@Component({
  selector: 'app-user-list',
  template: `
    <div *ngFor="let item of users | keyvalue">
      <p>Ключ: {{ item.key }}</p>
      <p>Имя: {{ item.value.name }}</p>
      <p>Возраст: {{ item.value.age }}</p>
      <hr>
    </div>
  `
})
export class UserListComponent {
  users: { [key: string]: User } = {
    user1: { name: 'Иван', age: 30 },
    user2: { name: 'Мария', age: 25 },
    user3: { name: 'Петр', age: 35 }
  };
}

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

  • Пайп keyvalue преобразует объект в массив объектов с полями key (ключ) и value (значение).
  • Вы можете использовать стандартный синтаксис *ngFor для перебора полученного массива.
  • Доступ к полям осуществляется через item.key (ключ) и item.value (значение).

Сортировка ключей

По умолчанию KeyValuePipe сортирует ключи в алфавитном порядке. Если вам нужно сохранить исходный порядок, используйте параметр compareFn:

// В шаблоне
<div *ngFor="let item of users | keyvalue: originalOrder">

// В компоненте
originalOrder(a: KeyValue<string, User>, b: KeyValue<string, User>): number {
  return 0; // Сохраняет исходный порядок
}

Альтернативный способ с Object.keys()

Если по каким-то причинам вы не хотите использовать пайп, можно преобразовать объект в массив в самом компоненте:

// В компоненте
export class UserListComponent {
  users = { ... };
  
  getUsersAsArray() {
    return Object.keys(this.users).map(key => ({
      key: key,
      value: this.users[key]
    }));
  }
}

// В шаблоне
<div *ngFor="let item of getUsersAsArray()">
  {{ item.key }}: {{ item.value.name }}
</div>

Важные замечания

  • Производительность: KeyValuePipe создает новый массив при каждом цикле обнаружения изменений. Для больших объектов (более 1000 элементов) лучше использовать подход с преобразованием в компоненте.
  • Типизация: TypeScript автоматически определит типы для item.key (string) и item.value (ваш тип данных).
  • Изменяемость: Если вы изменяете объект динамически (добавляете/удаляете ключи), Angular автоматически обновит отображение.

Используйте KeyValuePipe — это наиболее идиоматичный способ работы с объектами в Angular шаблонах.

<<>>

Создание пользовательского пайпа для кастомной логики

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

// custom-keyvalue.pipe.ts
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'customKeyValue',
  pure: false // Обновляется при каждом изменении
})
export class CustomKeyValuePipe implements PipeTransform {
  transform(obj: any): any[] {
    if (!obj) return [];
    return Object.keys(obj).map(key => ({
      key,
      value: obj[key],
      // Можно добавить дополнительные поля
      isEven: parseInt(key.replace('user', '')) % 2 === 0
    }));
  }
}

// Использование в шаблоне
<div *ngFor="let item of users | customKeyValue">
  {{ item.key }} - {{ item.value.name }}
  <span *ngIf="item.isEven">(четный)</span>
</div>

Этот подход полезен, когда нужно добавить вычисляемые поля или отфильтровать некоторые ключи. Помните, что pure: false может снизить производительность, используйте его только при необходимости динамического обновления.