Etwas verwirrt darüber, wie ein Key and Value
eines Objekts in angle2 abgerufen wird, während * ngFor für die Iteration des Objekts verwendet wird. Ich weiß in Winkel 1.x gibt es Syntax wie
ng-repeat="(key, value) in demo"
aber in Angle2 weiß ich nicht, dass ich dasselbe versucht habe, aber nicht erfolgreich war. Ich habe den folgenden Code ausprobiert, aber nicht ausgeführt, bitte sagen Sie mir, wo ich falsch arbeite.
<ul>
<li *ngFor='#key of demo'>{{key}}</li>
</ul>
demo = {
'key1': [{'key11':'value11'}, {'key12':'value12'}],
'key2': [{'key21':'value21'}, {'key22':'value22'}],
}
hier ist plnkr, wo ich das gleiche ausprobiert habe: http://plnkr.co/edit/mIj619FncOpfdwrR0KeG?p=preview
Ich möchte key1
und key2
mit * ngFor dynamisch abrufen. Wie bekomme ich das? Ich habe viel nach der Idee gesucht, Pipe zu benutzen, aber wie ich es benutze, weiß ich nicht ... Gibt es eine Inbuild-Pipe, um dasselbe in Angle2 zu tun?
Wie in latest Version von Angular (v6.1.0) hat Angular Team eine neue eingebaute Pipe für die gleichnamige keyvalue
-Pipe hinzugefügt, mit der Sie Objekte, Karten und Arrays im common
-Modul des Winkelpakets durchlaufen können .Zum Beispiel -
<div *ngFor="let item of testObject | keyvalue">
Key: <b>{{item.key}}</b> and Value: <b>{{item.value}}</b>
</div>
hier finden Sie weitere nützliche Informationen.
Wenn Sie Angular v5 oder darunter verwenden oder die Verwendung von Pipe erreichen möchten, folgen Sie dieser Antwort
Habe Object.keys
in der Vorlage verfügbar und verwende es in *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(){}
}
Sie können eine benutzerdefinierte Pipe erstellen, um die Liste der Schlüssel für jedes Element zurückzugeben. __ So ähnlich:
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;
}
}
und benutze es so:
<tr *ngFor="let c of content">
<td *ngFor="let key of c | keys">{{key}}: {{c[key]}}</td>
</tr>
Bearbeiten
Sie können auch einen Eintrag mit Schlüssel und Wert zurückgeben:
@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;
}
}
und benutze es so:
<span *ngFor="let entry of content | keys">
Key: {{entry.key}}, value: {{entry.value}}
</span>
In 6.1.0-beta.1KeyValuePipewurde _ eingeführt https://github.com/angular/angular/pull/24319
<div *ngFor="let item of {'b': 1, 'a': 1} | keyvalue">
{{ item.key }} - {{ item.value }}
</div>
Ein anderer Ansatz ist die Erstellung einer NgForIn
Direktive, die wie folgt verwendet wird:
<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);
}
}
}
Ausarbeitung der Antwort von @ Thierry mit Beispiel.
Es gibt keine eingebaute Pipe oder Methode, um key and value
aus der * ngFor-Schleife zu erhalten. Wir müssen also eine eigene Pipe erstellen. Wie Thierry sagte, hier ist die Antwort mit Code.
** Die Pipe-Klasse implementiert die Transformationsmethode der PipeTransform-Schnittstelle, die einen Eingabewert und ein optionales Array von Parameterzeichenfolgen verwendet und den transformierten Wert zurückgibt.
** Die Transformationsmethode ist für eine Pipe unerlässlich. Die PipeTransform-Schnittstelle definiert diese Methode und leitet sowohl das Tooling als auch den Compiler. Es ist optional; Angular sucht und führt die Transformationsmethode unabhängig davon aus . Weitere Informationen zu Pipe siehe hier
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;
}
}
und HTML-Teil ist:
<ul>
<li *ngFor='#key of demo | keys'>
Key: {{key.key}}, value: {{key.value}}
</li>
</ul>
Working Plnkr http://plnkr.co/edit/50LlK0k6OnMnkc2kNHM2?p=preview
wie von user6123723 (danke) in kommentar hier vorgeschlagen, ist update.
<ul>
<li *ngFor='let key of demo | keys'>
Key: {{key.key}}, value: {{key.value}}
</li>
</ul>
@Marton hatte einen wichtigen Einwand gegen die akzeptierte Antwort mit der Begründung, dass die Pipe bei jeder Änderungserkennung eine neue Sammlung erstellt. Ich würde stattdessen einen HtmlService erstellen, der eine Reihe von Hilfsfunktionen bereitstellt, die die Ansicht wie folgt verwenden kann:
@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...
}
Ab Angular 6.1 können Sie den Schlüsselwert pipe verwenden:
<div *ngFor="let item of testObject | keyvalue">
Key: <b>{{item.key}}</b> and Value: <b>{{item.value}}</b>
</div>
Es hat jedoch den Nachteil, dass die Ergebnisliste nach dem Schlüsselwert sortiert wird. Wenn Sie etwas Neutrales benötigen:
@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;
}
}
Vergessen Sie nicht, das Attribut pure: false pipe anzugeben. In diesem Fall wird die Pipe bei jedem Änderungserkennungszyklus aufgerufen, auch wenn sich die Eingabereferenz nicht geändert hat (wenn Sie einem Objekt Eigenschaften hinzufügen).
Wenn Sie Lodash bereits verwenden, können Sie diesen einfachen Ansatz verwenden, der sowohl Schlüssel als auch Wert beinhaltet:
<ul>
<li *ngFor='let key of _.keys(demo)'>{{key}}: {{demo[key]}}</li>
</ul>
Fügen Sie in der TypeScript-Datei Folgendes hinzu:
import * as _ from 'lodash';
und in der exportierten Komponente Folgendes enthalten:
_: any = _;
Vielen Dank für das Rohr, aber ich musste einige Änderungen vornehmen, bevor ich es in eckig 2 RC5 verwenden konnte. Die Pipe-Importlinie wurde geändert und der Initialisierung des Key-Arrays wurde der Typ any hinzugefügt.
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;
}
}
Es gibt eine echte Nice-Bibliothek, die dies unter anderen Nice-Pfeifen tut. Es heißt ngx-pipe .
Zum Beispiel gibt key pipe Schlüssel für ein Objekt zurück, und values pipe gibt Werte für ein Objekt zurück:
keys pipe
<div *ngFor="let key of {foo: 1, bar: 2} | keys">{{key}}</div>
<!-- Output: 'foo' and 'bar -->
Wertepipe
<div *ngFor="let value of {foo: 1, bar: 2} | values">{{value}}</div>
<!-- Output: 1 and 2 -->
Sie müssen keine eigene Pipe erstellen :)
Keine der Antworten hier hat für mich aus dem Kasten heraus funktioniert.
Erstellen Sie pipes/keys.ts
mit Inhalt:
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;
}
}
Zu app.module.ts
hinzufügen (Ihr Hauptmodul):
import { KeysPipe } from './pipes/keys';
und fügen Sie dann zu Ihrem Modul Deklarationsarray etwas hinzu:
@NgModule({
declarations: [
KeysPipe
]
})
export class AppModule {}
Dann können Sie in Ihrer Ansichtsvorlage Folgendes verwenden:
<option *ngFor="let entry of (myData | keys)" value="{{ entry.key }}">{{ entry.value }}</option>
Hier ist eine gute Referenz, die ich gefunden habe, wenn Sie mehr lesen möchten.
Hier ist die einfache Lösung
Sie können dafür TypeScript-Iteratoren verwenden
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]
}
}
}
};
}
}
Ändern Sie den Demo-Typ in Array oder iterieren Sie über Ihr Objekt und drücken Sie auf ein anderes Array
public details =[];
Object.keys(demo).forEach(key => {
this.details.Push({"key":key,"value":demo[key]);
});
und von html:
<div *ngFor="obj of details">
<p>{{obj.key}}</p>
<p>{{obj.value}}</p>
<p></p>
</div>
Index verwenden:
<div *ngFor="let value of Objects; index as key">
Verwendungszweck:
{{key}} -> {{value}}
Ich denke, Object.keys ist die beste Lösung für dieses Problem. Für jeden, der auf diese Antwort stößt und herauszufinden versucht, warum Object.keys ihnen ['0', '1'] anstelle von ['key1', 'key2'] gibt, ist dies eine warnende Geschichte - hüten Sie den Unterschied zwischen " von "und" in ":
Ich habe bereits Object.keys verwendet, etwas ähnliches:
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;
}
Statt jedoch
for (const key OF Object.keys(mydemo)) {
Ich hatte versehentlich geschrieben
for (const key IN Object.keys(mydemo)) {
die "funktionierte" einwandfrei ohne fehler und kehrte zurück
[{key: '0', value: undefined}, {key: '1', value: undefined}]
Das kostete mich etwa 2 Stunden googeln und fluchen.
(Ohrfeigen)
wenn Sie dies versuchen, erhalten Sie den Schlüssel des dynamischen Objekts von dynamic
myObj['key']
Sie müssen es erst einmal so machen, ich weiß es nicht sehr effizient, da Sie das Objekt, das Sie von Firebase erhalten, nicht konvertieren wollen.
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;
});