Как перебрать свойства объекта с помощью ngFor в Angular

Это пост об интересной проблеме, которую я нашел на работе.

Если вы еще этого не знаете. Я говорю об Angular 2+

Эта проблема

Таким образом, вы хотите отобразить разметку для списка, значения для этого списка берутся из внутреннего интерфейса и по какой-то причине вместо старого доброго массива объектов вы получаете что-то вроде этого.

    { 
  "car" : 
    { 
       "color" : "red",
       "model" : "2013"
    },
   "motorcycle": 
    { 
       "color" : "red",
       "model" : "2016"
    },
   "bicycle": 
    { 
       "color" : "red",
       "model" : "2011"
    }
}

Затем вы пытаетесь использовать * ngFor, но появляется сообщение об ошибке:

Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.

Вы можете исправить это в бэкэнде, чтобы получить массив объектов, но у вас нет времени для этого. Не волнуйся, дитя, я поймал нас.

9 ответов

В Angular 6.1 была введена KeyValuePipe, которая позволяет перебирать свойства объекта:

<div *ngFor="let item of object | keyvalue">
  {{item.key}}:{{item.value}}
</div>

Документы: https://angular.io/api/common/KeyValuePipe

Я не знаю, насколько это безопасно, но в этих простых случаях мне не нравится решение для канала, поэтому я обычно использую:

<div *ngFor="let k of objectKeys(yourObject)">
    {{yourObject[k].color}}
</div>

и в контроллере:

objectKeys(obj) {
    return Object.keys(obj);
}

Это довольно частый случай, я не понимаю, почему нет стандартной реализации для этого, как в Angular.js 1.x

Лучшим решением было бы использовать трубу, такую ​​как эта:

import { Pipe, PipeTransform } from '@angular/core';

/**
 * Convert Object to array of keys.
 */
@Pipe({
  name: 'appProperties'
})
export class PropertiesPipe implements PipeTransform {

  transform(value: {}): string[] {

    if (!value) {
      return [];
    }

    return Object.keys(value);
  }
}

Тогда в вашем шаблоне:

<div *ngFor="let property of response | appProperties">
    <div *ngFor="let item of response[property]">
         {{item.something}}
    </div>
</div>
    <div *ngFor="let item of donation_list | keyvalue">
        <div class="donation-box">
             <Label class="donation-label">Date : {{item.value.PaymentDate}}</Label>
             <Label class="donation-label">Time : {{item.value.PaymentTime}}</Label>

        </div>
   </div>

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

Есть 2 способа:

  1. Если у ваших объектов нет ключа

            { name: 'John', age: 18,... }
    
    <div *ngFor="let item of myObj | keyvalue">
        Key: <strong>{{item.key}}</strong> and Value: <span>{{item.value}}</span>
    </div>
    
  2. Если у ваших объектов есть ключ

    Трубка

            import { Pipe, PipeTransform } from "@angular/core";
    
    type Args = "keyvalue" | "value" | "key";
    
    @Pipe({
        name: "pipeMapToIterable",
        pure: false
    })
    export class MapToIterablePipe implements PipeTransform {
        transform(obj: {}, arg: Args = "keyvalue") {
            return arg === "keyvalue" ?
                Object.keys(obj).map(key => ({ key: key, value: obj[key] })) :
                arg === "key" ?
                    Object.keys(obj) :
                    arg === "value" ?
                        Object.keys(obj).map(key => obj[key]) :
                        null;
        }
    }
    

    HTML

            { 
        John: { name: 'John', age: 18 },
        Bob: { name: 'Bob', age: 25},
        Marry: { name: 'Marry', age: 22}
    }
    
    <!-- default -->
    <div *ngFor="let item of myObj | pipeMapToIterable">
        Key: <strong>{{item.key}}</strong> and Value: <span>{{item.value}</span>
    </div>
    
    
    <!-- keyvalue -->
    <div *ngFor="let item of myObj | pipeMapToIterable : 'keyvalue'">
        Key: <strong>{{item.key}}</strong> and Value: <span>{{item.value}</span>
    </div>
    
    
    <!-- value -->
    <div *ngFor="let item of myObj | pipeMapToIterable : 'value'">
        Key: <strong>{{item.key}}</strong> and Value: <span>{{item.value}</span>
    </div>
    
    
    <!-- key -->
    <div *ngFor="let item of myObj | pipeMapToIterable : 'key'">
        Key: <strong>{{item.key}}</strong> and Value: <span>{{item.value}</span>
    </div>
    

Используйте Object.values, чтобы получить из вашего объекта обычный массив. Object.keys кажется лишней работой.

Ссылка:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Object/values

Решение

В идеальном мире вы получите множество объектов, поскольку мир не всегда идеален. Что вы хотите сделать, это хранить все эти объекты в массиве. Вот упрощенное решение в простом старом JavaScript.

Шаг 1. Получить все ключи объекта. используя Object.keys. Этот метод возвращает массив собственных перечисляемых свойств данного объекта.

Шаг 2. Создайте пустой массив. Это то место, где будут жить все свойства, так как ваш новый цикл ngFor будет указывать на этот массив, мы должны перехватить их все.

Шаг 3. Выполните итерацию throw всех ключей и вставьте каждый в созданный вами массив.

Вот как это выглядит в коде.

// Evil response in a variable. Here are all my vehicles.
let evilResponse = { 
  "car" : 
    { 
       "color" : "red",
       "model" : "2013"
    },
   "motorcycle": 
    { 
       "color" : "red",
       "model" : "2016"
    },
   "bicycle": 
    { 
       "color" : "red",
       "model" : "2011"
    }
}
// Step 1. Get all the object keys.
let evilResponseProps = Object.keys(evilResponse);
// Step 2. Create an empty array.
let goodResponse = [];
// Step 3. Iterate throw all keys.
for (prop of evilResponseProps) { 
    goodResponse.push(evilResponseProps[prop]);
}

Затем вы можете назначить goodResponse свойству класса, которое вы пытались выполнить в первую очередь.

Это все, ребята.

Вы можете попробовать это:

      <div *ngFor="let item of object | keyvalue">
  {{item.key}}:{{item.value}}
</div>

Для получения дополнительной информации посетите: https://angular.io/api/common/KeyValuePipe

объявите свой массив как любой, а затем назначьте свой объект

      data=[] as any;
myObj={};

data=myObj;

теперь прокручиваем массив данных

      <tr *ngFor="let item of data">
<td>{{item.property}}</td>
</tr>
Другие вопросы по тегам