web-dev-qa-db-fra.com

Comment boucler sur les propriétés d'un objet avec ngFor dans Angular

ce post concerne un problème intéressant que j'ai trouvé au travail.

Si vous ne le savez pas encore. Je parle de Angular 2+

Le problème

Donc, si vous voulez afficher le balisage d'une liste, les valeurs de cette liste proviennent du serveur principal et, pour une raison quelconque, au lieu d'un bon vieux tableau d'objets, vous recevez quelque chose comme ceci.

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

Vous essayez ensuite d’utiliser * ngFor mais un message d’erreur sauvage apparaît:

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

Vous pouvez le réparer dans l’arrière-plan afin d’obtenir un tableau d’objets, mais aucun organisme n’a le temps de le faire. Ne vous inquiétez pas enfant, je nous ai eu.

17
Jaime Rios

Dans Angular 6.1, KeyValuePipe a été introduit pour vous permettre d’itérer les propriétés de l’objet:

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

Docs: https://angular.io/api/common/KeyValuePipe

39
danday74

Je ne sais pas si cela est sans danger, mais pour ces cas simples, je n'aime pas la solution de canalisation, donc j'utilise habituellement:

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

et dans le contrôleur:

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

C'est un cas assez fréquent, je ne comprends pas pourquoi il n'y a pas d'implémentation standard pour cela comme dans Angular.js 1.x

14
m__

Une meilleure solution serait d’utiliser un tuyau comme celui-ci:

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);
  }
}

Puis dans votre modèle:

<div *ngFor="let property of response | appProperties">
    <div *ngFor="let item of response[property]">
         {{item.something}}
    </div>
</div>
10
Matsura

La solution

Dans un monde parfait, vous obtiendrez un tableau d'objets, car le monde n'est pas toujours parfait. Ce que vous voulez faire, c'est stocker tous ces objets dans un tableau. Voici une solution trop simpliste en JavaScript ancien et simple.

Étape 1. Récupère toutes les clés d'objet. en utilisant Object.keys. Cette méthode retourne un tableau des propriétés énumérables propres à un objet donné.

Étape 2. Créez un tableau vide. C’est un endroit où toutes les propriétés vont vivre, puisque votre nouvelle boucle ngFor va pointer vers ce tableau, nous devons toutes les attraper.

Étape 3. Iterate lance toutes les clés et pousse chacune d'elles dans le tableau que tu as créé.

Voici à quoi cela ressemble dans le code.

// 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]);
}

Ensuite, vous pouvez affecter la bonne réponse à la propriété de classe que vous tentiez de lire en premier lieu.

C’est tout.

1
Jaime Rios
    <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>

Si vous avez plus de propriétés à l'intérieur de l'objet, vous pouvez utiliser comme ceci.

1
ChamodyaDias