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?
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>
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
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(){}
}
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>
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>
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>
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);
}
}
}
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
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>
@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...
}
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).
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 = _;
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;
}
}
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 :)
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.
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]
}
}
}
};
}
}
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>
Indice d'utilisation:
<div *ngFor="let value of Objects; index as key">
Usage:
{{key}} -> {{value}}
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)
vous pouvez obtenir la clé de l'objet dynamique avec en essayant ceci
myObj['key']
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;
});