web-dev-qa-db-fra.com

clé d'accès et valeur de l'objet avec * ngFor

Bit confus sur la façon d'obtenir Key and Value d'un objet dans angular2 en utilisant * ngFor pour une itération sur l'objet Je sais que dans 1.x angulaire il y a une syntaxe comme 

ng-repeat="(key, value) in demo"

mais dans angular2, je ne sais pas, j'ai essayé la même chose mais sans succès. J'ai essayé le code ci-dessous mais je n'ai pas couru s'il vous plaît dites-moi où je me trompe.

<ul>
  <li *ngFor='#key of demo'>{{key}}</li>
</ul>

demo = {
    'key1': [{'key11':'value11'}, {'key12':'value12'}],
    'key2': [{'key21':'value21'}, {'key22':'value22'}],
  }

voici la plnkr où j'ai essayé la même chose: http://plnkr.co/edit/mIj619FncOpfdwrR0KeG?p=preview

Je veux obtenir key1 et key2 de manière dynamique en utilisant * ngFor. Comment l'obtenir? J'ai beaucoup cherché l'idée d'utiliser un tuyau, mais comment l'utiliser, je ne sais pas . Existe-t-il des pipes inbuild pour faire la même chose dans angular2?

249
Pardeep Jain

Comme dans dernière version de Angular (v6.1.0), Angular Team a ajouté un nouveau canal intégré portant le même tube, nommé keyvalue, afin de vous aider à parcourir des objets, des cartes et des tableaux dans le module common du package angulaire. .Par exemple -

<div *ngFor="let item of testObject | keyvalue">
    Key: <b>{{item.key}}</b> and Value: <b>{{item.value}}</b>
</div>

Exemple de travail à la fourche

consultez ici pour plus d'informations utiles -

Si vous utilisez Angular v5 ou inférieur ou si vous voulez utiliser un tuyau, suivez cette réponse

104
Pardeep Jain

Ayez Object.keys accessible dans le modèle et utilisez-le dans *ngFor.

@Component({
  selector: 'app-myview',
  template: `<div *ngFor="let key of objectKeys(items)">{{key + ' : ' + items[key]}}</div>`
})

export class MyComponent {
  objectKeys = Object.keys;
  items = { keyOne: 'value 1', keyTwo: 'value 2', keyThree: 'value 3' };
  constructor(){}
}
272
tomtastico

Vous pouvez créer un canal personnalisé pour renvoyer la liste des clés pour chaque élément . Quelque chose comme ça:

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

@Pipe({name: 'keys'})
export class KeysPipe implements PipeTransform {
  transform(value, args:string[]) : any {
    let keys = [];
    for (let key in value) {
      keys.Push(key);
    }
    return keys;
  }
}

et l'utiliser comme ça:

<tr *ngFor="let c of content">           
  <td *ngFor="let key of c | keys">{{key}}: {{c[key]}}</td>
</tr>

Modifier

Vous pouvez également renvoyer une entrée contenant à la fois la clé et la valeur:

@Pipe({name: 'keys'})
export class KeysPipe implements PipeTransform {
  transform(value, args:string[]) : any {
    let keys = [];
    for (let key in value) {
      keys.Push({key: key, value: value[key]});
    }
    return keys;
  }
}

et l'utiliser comme ça:

<span *ngFor="let entry of content | keys">           
  Key: {{entry.key}}, value: {{entry.value}}
</span>
195
Thierry Templier

Mettre à jour

En 6.1.0-beta.1 _ {KeyValuePipe a été introduit https://github.com/angular/angular/pull/24319

<div *ngFor="let item of {'b': 1, 'a': 1} | keyvalue">
  {{ item.key }} - {{ item.value }}
</div>

Exemple Plunker

La version précédente

Une autre approche consiste à créer une directive NgForIn qui sera utilisée comme suit:

<div *ngFor="let key in obj">
   <b>{{ key }}</b>: {{ obj[key] }}
</div>

Exemple Plunker

ngforin.directive.ts

@Directive({
  selector: '[ngFor][ngForIn]'
})
export class NgForIn<T> extends NgForOf<T> implements OnChanges {

  @Input() ngForIn: any;

  ngOnChanges(changes: NgForInChanges): void {
    if (changes.ngForIn) {
      this.ngForOf = Object.keys(this.ngForIn) as Array<any>;

      const change = changes.ngForIn;
      const currentValue = Object.keys(change.currentValue);
      const previousValue = change.previousValue ? Object.keys(change.previousValue) : undefined;
      changes.ngForOf =  new SimpleChange(previousValue, currentValue, change.firstChange);

      super.ngOnChanges(changes);
    }
  }
}
32
yurzui

Elaboration de la réponse de @ Thierry avec des exemples.

Il n'y a pas de pipe ou méthode incorporée pour obtenir key and value à partir de la boucle * ngFor. nous devons donc créer un tuyau personnalisé pour la même chose. comme thierry a dit voici la réponse avec le code.

** La classe pipe implémente la méthode de transformation de l'interface PipeTransform qui prend une valeur d'entrée et un tableau facultatif de chaînes de paramètres et renvoie la valeur transformée.

** La méthode de transformation est essentielle à un tuyau. L'interface PipeTransform définit cette méthode et guide à la fois l'outillage et le compilateur. C'est optionnel. Angular recherche et exécute la méthode de transformation indépendamment de . Pour plus d'informations sur pipe référez-vous ici

import {Component, Pipe, PipeTransform} from 'angular2/core';
import {CORE_DIRECTIVES, NgClass, FORM_DIRECTIVES, Control, ControlGroup, FormBuilder, Validators} from 'angular2/common';

@Component({
    selector: 'my-app',
    templateUrl: 'mytemplate.html',
    directives: [CORE_DIRECTIVES, FORM_DIRECTIVES],
    pipes: [KeysPipe]
})
export class AppComponent { 

  demo = {
    'key1': 'ANGULAR 2',
    'key2': 'Pardeep',
    'key3': 'Jain',
  }
}


@Pipe({name: 'keys'})
export class KeysPipe implements PipeTransform {
  transform(value, args:string[]) : any {
    let keys = [];
    for (let key in value) {
      keys.Push({key: key, value: value[key]});
    }
    return keys;
  }
}

et la partie HTML est: 

<ul>
  <li *ngFor='#key of demo | keys'>
   Key: {{key.key}}, value: {{key.value}}
  </li>
</ul>

Working Plnkr http://plnkr.co/edit/50LlK0k6OnMnkc2kNHM2?p=preview

mise à jour vers RC

comme suggéré par user6123723 (merci) dans le commentaire ici est mise à jour.

<ul>
  <li *ngFor='let key of demo | keys'>
   Key: {{key.key}}, value: {{key.value}}
  </li>
</ul>
23
Pardeep Jain

@Marton avait une objection importante à la réponse acceptée au motif que le canal crée une nouvelle collection à chaque détection de changement. Je créerais plutôt un HtmlService qui fournit une gamme de fonctions utilitaires que la vue peut utiliser comme suit:

@Component({
  selector: 'app-myview',
  template: `<div *ngFor="let i of html.keys(items)">{{i + ' : ' + items[i]}}</div>`
})
export class MyComponent {
  items = {keyOne: 'value 1', keyTwo: 'value 2', keyThree: 'value 3'};
  constructor(private html: HtmlService){}
}

@Injectable()
export class HtmlService {
  keys(object: {}) {
    return Object.keys(object);
  }
  // ... other useful methods not available inside html, like isObject(), isArray(), findInArray(), and others...
}
18
Stephen Paul

Depuis Angular 6.1, vous pouvez utiliser la valeur keyvalue pipe:

<div *ngFor="let item of testObject | keyvalue">
    Key: <b>{{item.key}}</b> and Value: <b>{{item.value}}</b>
</div>

Mais il a l'inconvénient de trier la liste résultante par la valeur de clé . Si vous avez besoin de quelque chose de neutre:

@Pipe({ name: 'keyValueUnsorted', pure: false  })
export class KeyValuePipe implements PipeTransform {
  transform(input: any): any {
    let keys = [];
    for (let key in input) {
      if (input.hasOwnProperty(key)) {
        keys.Push({ key: key, value: input[key]});
      }
    }
    return keys;
  }
}

N'oubliez pas de spécifier l'attribut pure: false pipe. Dans ce cas, le canal est appelé à chaque cycle de détection de changement, même si la référence d'entrée n'a pas changé (c'est le cas lorsque vous ajoutez des propriétés à un objet). 

16
Gerard Carbó

Si vous utilisez déjà Lodash, vous pouvez utiliser cette approche simple qui comprend à la fois une clé et une valeur

<ul>
  <li *ngFor='let key of _.keys(demo)'>{{key}}: {{demo[key]}}</li>
</ul>

Dans le fichier TypeScript, incluez:

import * as _ from 'lodash';

et dans le composant exporté, inclure:

_: any = _;
15
Jeremy Moritz

Merci pour le tuyau, mais j'ai dû faire quelques changements avant de pouvoir l'utiliser dans angular 2 RC5. Modification de la ligne d'importation de canalisation et ajout du type de l'un quelconque à l'initialisation du tableau de clés.

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

 @Pipe({name: 'keys'})
 export class KeysPipe implements PipeTransform {
 transform(value) {
   let keys:any = [];
   for (let key in value) {
      keys.Push( {key: key, value: value[key]} );
    }
     return keys;
  }
}
8
Adam Winnipass

Il y a une vraie bibliothèque Nice qui fait cela parmi d'autres pipes Nice. Cela s'appelle ngx-pipes

Par exemple, keys pipe renvoie les clés d'un objet et values ​​pipe renvoie les valeurs d'un objet:

touches pipe

<div *ngFor="let key of {foo: 1, bar: 2} | keys">{{key}}</div> 
<!-- Output: 'foo' and 'bar -->

valeurs pipe

<div *ngFor="let value of {foo: 1, bar: 2} | values">{{value}}</div>
<!-- Output: 1 and 2 -->

Pas besoin de créer votre propre pipe personnalisée :)

6
RichieRock

Aucune des réponses ici n'a fonctionné pour moi hors de la boîte, voici ce qui a fonctionné pour moi:

Créez pipes/keys.ts avec le contenu:

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

@Pipe({name: 'keys'})
export class KeysPipe implements PipeTransform
{
    transform(value:any, args:string[]): any {
        let keys:any[] = [];
        for (let key in value) {
            keys.Push({key: key, value: value[key]});
        }
        return keys;
    }
}

Ajouter à app.module.ts (Votre module principal):

import { KeysPipe } from './pipes/keys';

puis ajoutez à votre tableau de déclarations de module quelque chose comme ceci:

@NgModule({
    declarations: [
        KeysPipe
    ]
})
export class AppModule {}

Ensuite, dans votre modèle de vue, vous pouvez utiliser quelque chose comme ceci:

<option *ngFor="let entry of (myData | keys)" value="{{ entry.key }}">{{ entry.value }}</option>

Ici est une bonne référence que j'ai trouvée si vous voulez lire plus.

6
cjohansson

Voici la solution simple

Vous pouvez utiliser les itérateurs TypeScript pour cela

import {Component} from 'angular2/core';
declare var Symbol;
@Component({
    selector: 'my-app',
    template:`<div>
    <h4>Iterating an Object using TypeScript Symbol</h4><br>
Object is : <p>{{obj | json}}</p>
</div>
============================<br>
Iterated object params are:
<div *ngFor="#o of obj">
{{o}}
</div>

`
})
export class AppComponent {
  public obj: any = {
    "type1": ["A1", "A2", "A3","A4"],
    "type2": ["B1"],
    "type3": ["C1"],
    "type4": ["D1","D2"]
  };

  constructor() {
    this.obj[Symbol.iterator] =  () => {
          let i =0;

          return {
            next: () => {
              i++;
              return {
                  done: i > 4?true:false,
                  value: this.obj['type'+i]
              }
            }
          }
    };
  }
}

http://plnkr.co/edit/GpmX8g?p=info

3
sudheer KB

changez le type de démonstration en tableau .__ ou faites une itération sur votre objet et appuyez sur un autre tableau

public details =[];   
Object.keys(demo).forEach(key => {
      this.details.Push({"key":key,"value":demo[key]);
    });

et de html: 

<div *ngFor="obj of details">
  <p>{{obj.key}}</p>
  <p>{{obj.value}}</p>
  <p></p>
</div>
1
Mohammad Reza Mrg

Indice d'utilisation:

<div *ngFor="let value of Objects; index as key">

Usage:

{{key}} -> {{value}}
1
Adonias Vasquez

Je pense que Object.keys est la meilleure solution à ce problème. Pour tous ceux qui rencontrent cette réponse et qui cherchent à savoir pourquoi Object.keys leur donne ['0', '1'] au lieu de ['key1', 'key2'], un récit édifiant: attention à la différence de "et" dans ":

J'utilisais déjà Object.keys, quelque chose de similaire à ceci: 

interface demo {
    key: string;
    value: string;
}

createDemo(mydemo: any): Array<demo> {
    const tempdemo: Array<demo> = [];

    // Caution: use "of" and not "in"
    for (const key of Object.keys(mydemo)) {
        tempdemo.Push(
            { key: key, value: mydemo[key]}
        );
    }

    return tempdemo;
}

Cependant, au lieu de 

for (const key OF Object.keys(mydemo)) {

J'avais écrit par inadvertance

for (const key IN Object.keys(mydemo)) {

qui "fonctionnait" parfaitement bien sans aucune erreur et retourné 

[{key: '0', value: undefined}, {key: '1', value: undefined}]

Cela m'a coûté environ 2 heures à googler et à maudire ..

(claque le front)

1
Ciaran Bruen

vous pouvez obtenir la clé de l'objet dynamique avec en essayant ceci

myObj['key']
0
Rizo

Vous devez le faire comme ceci pour le moment, je sais pas très efficace car vous ne voulez pas convertir l'objet que vous recevez de firebase.

    this.af.database.list('/data/' + this.base64Email).subscribe(years => {
        years.forEach(year => {

            var localYears = [];

            Object.keys(year).forEach(month => {
                localYears.Push(year[month])
            });

            year.months = localYears;

        })

        this.years = years;

    });
0
kevinius