Iterare su un object in Angolare

Sto cercando di fare alcune cose in Angular 2 Alpha 28 e sto avendo un problema con i dizionari e NgFor.

Ho un’interfaccia in TypeScript simile a questa:

interface Dictionary { [ index: string ]: string } 

In JavaScript questo si tradurrà in un object che con i dati potrebbe apparire come questo:

 myDict={'key1':'value1','key2':'value2'} 

Voglio ripetere questo e ho provato questo:

 
{{key}}:{{value}}

Ma inutilmente, nessuno dei seguenti ha funzionato:

 
{{value}}
{{key}}:{{value}}

In tutti i casi ottengo errori come “Token inaspettato” o “Imansible trovare ‘object di supporto pipe iterableDiff”

Cosa mi manca qui? Non è più ansible? (La prima syntax funziona in 1.x angular) oppure la syntax è differente per iterare su un object?

Sembra che non vogliano supportare la syntax di ng1.

Secondo Miško Hevery ( riferimento ):

Le mappe non hanno ordini nelle chiavi e quindi l’iterazione è imprevedibile. Questo è stato supportato in ng1, ma pensiamo che sia stato un errore e non sarà supportato in NG2

Il piano è di avere un tubo mapToIterable

Quindi per iterare sul tuo object dovrai usare un “pipe”. Attualmente non è implementato alcun tubo che lo faccia.

Come soluzione, ecco un piccolo esempio che scorre le chiavi:

Componente:

 import {Component} from 'angular2/core'; @Component({ selector: 'component', templateUrl: ` 
  • {{key}}:{{myDict[key]}}
` }) export class Home { myDict : Dictionary; constructor() { this.myDict = {'key1':'value1','key2':'value2'}; } keys() : Array { return Object.keys(this.myDict); } } interface Dictionary { [ index: string ]: string }

prova ad usare questa pipa

 @Pipe({ name: 'values', pure: false }) export class ValuesPipe implements PipeTransform { transform(value: any, args: any[] = null): any { return Object.keys(value).map(key => value[key]); } } 

Aggiornamento 2018 :

Come le altre risposte hanno menzionato, non è supportato in ngx, quindi ecco una soluzione alternativa con coppie chiave-valore :

La pipa:

 import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'mapToIterable' }) export class MapToIterable implements PipeTransform { transform(dict: Object) { var a = []; for (var key in dict) { if (dict.hasOwnProperty(key)) { a.push({key: key, val: dict[key]}); } } return a; } } 

L’utilizzo:

 
This is the key {{keyValuePair.key}} and this is the value {{keyValuePair.val}}.

Stackblitz Esempio: https://stackblitz.com/edit/map-to-iterable-pipe

Oltre alla risposta di @ oscur, ecco un esempio di come è ansible accedere sia alla key che al value da @View.

Tubo:

 @Pipe({ name: 'keyValueFilter' }) export class keyValueFilterPipe { transform(value: any, args: any[] = null): any { return Object.keys(value).map(function(key) { let pair = {}; let k = 'key'; let v = 'value' pair[k] = key; pair[v] = value[key]; return pair; }); } } 

Vista:

 
  • First Name: {{u.key}}
    Last Name: {{u.value}}
  • Quindi se l’object dovesse apparire come:

     myObject = { Daario: Naharis, Victarion: Greyjoy, Quentyn: Ball } 

    Il risultato generato sarebbe:

    Nome: Daario
    Cognome: Naharis

    Nome: Victarion
    Cognome: Greyjoy

    Nome: Quentyn
    Cognome: Ball

    Aggiunta all’eccellente risposta di SimonHawesome. Ho fatto una versione succinta che utilizza alcune delle nuove funzionalità dattiloscritte. Mi rendo conto che la versione di SimonHawesome è intenzionalmente dettagliata per spiegare i dettagli sottostanti. Ho anche aggiunto un controllo anticipato in modo che la pipe funzioni per valori falsi . Ad esempio, se la mappa è null .

    Si noti che l’utilizzo di una trasformazione iteratore (come fatto qui) può essere più efficiente in quanto non è necessario allocare memoria per un array temporaneo (come fatto in alcune delle altre risposte).

     import {Pipe, PipeTransform} from '@angular/core'; @Pipe({ name: 'mapToIterable' }) export class MapToIterable implements PipeTransform { transform(map: { [key: string]: any }, ...parameters: any[]) { if (!map) return undefined; return Object.keys(map) .map((key) => ({ 'key': key, 'value': map[key] })); } } 

    Ecco una variazione su alcune delle risposte di cui sopra che supporta più trasformazioni (keyval, chiave, valore):

     import { Pipe, PipeTransform } from '@angular/core'; type Args = 'keyval'|'key'|'value'; @Pipe({ name: 'mapToIterable', pure: false }) export class MapToIterablePipe implements PipeTransform { transform(obj: {}, arg: Args = 'keyval') { return arg === 'keyval' ? 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; } } 

    uso

     map = { 'a': 'aee', 'b': 'bee', 'c': 'see' } 
    {{o.key}}: {{o.value}}
    a: aee
    b: bee
    c: see
    {{o.key}}: {{o.value}}
    a: aee
    b: bee
    c: see
    {{k}}
    a
    b
    c
    {{v}}
    aee
    bee
    see

    Ho avuto un problema simile, ho creato qualcosa per gli oggetti e Maps.

     import { Pipe } from 'angular2/core.js'; /** * Map to Iteratble Pipe * * It accepts Objects and [Maps](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) * * Example: * * 
    * key {{keyValuePair.key}} and value {{keyValuePair.value}} *
    * */ @Pipe({ name: 'mapToIterable' }) export class MapToIterable { transform(value) { let result = []; if(value.entries) { for (var [key, value] of value.entries()) { result.push({ key, value }); } } else { for(let key in value) { result.push({ key, value: value[key] }); } } return result; } }

    Angular 2.x && Angular 4.x non supportano questo fuori dalla scatola

    È ansible utilizzare questi due tubi per iterare sia per chiave che per valore .

    Tubo chiavi:

     import {Pipe, PipeTransform} from '@angular/core' @Pipe({ name: 'keys', pure: false }) export class KeysPipe implements PipeTransform { transform(value: any, args: any[] = null): any { return Object.keys(value) } } 

    Tubo dei valori:

     import {Pipe, PipeTransform} from '@angular/core' @Pipe({ name: 'values', pure: false }) export class ValuesPipe implements PipeTransform { transform(value: any, args: any[] = null): any { return Object.keys(value).map(key => value[key]) } } 

    Come usare:

     let data = {key1: 'value1', key2: 'value2'} 

    Se qualcuno si sta chiedendo come lavorare con oggetti multidimensionali, ecco la soluzione.

    Supponiamo di avere il seguente object in servizio

     getChallenges() { var objects = {}; objects['0'] = { title: 'Angular2', description : "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur." }; objects['1'] = { title: 'AngularJS', description : "Lorem Ipsum is simply dummy text of the printing and typesetting industry." }; objects['2'] = { title: 'Bootstrap', description : "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.", }; return objects; } 

    nel componente aggiungere la seguente funzione

     challenges; constructor(testService : TestService){ this.challenges = testService.getChallenges(); } keys() : Array { return Object.keys(this.challenges); } 

    finalmente in vista, segui

     

    {{challenges[key].title}}

    {{challenges[key].description}}

    Mi sono strappato i capelli cercando di analizzare e utilizzare i dati restituiti da una chiamata di query / api JSON. Non sono sicuro esattamente dove stavo sbagliando, mi sento come se stavo girando la risposta per giorni, inseguendo vari codici di errore come:

    “Imansible trovare ‘iterableDiff’ pipe supporting object”

    “Generic TYPE Array richiede un argomento (i)”

    JSON che analizza gli errori e sono sicuro che altri

    Im supponendo che ho appena avuto la combinazione sbagliata di correzioni.

    Quindi ecco un breve riassunto di trucchi e cose da cercare.

    Prima di tutto controlla il risultato delle tue chiamate API, i risultati possono essere sotto forma di un object, un array o una matrice di oggetti.

    non ci andrò troppo, basti dire che l’errore originale dell’OP di non essere iterabile è generalmente causato dal tentativo di iterare un object, non una matrice.

    Ecco alcuni dei miei risultati di debug che mostrano le variabili di entrambi gli array e gli oggetti

    Quindi, come in genere vorremmo ripetere il nostro risultato JSON, dobbiamo assicurarci che sia nella forma di una matrice. Ho provato numerosi esempi e forse sapendo quello che so ora alcuni di questi funzionerebbero, ma l’approccio con cui ho lavorato è stato quello di implementare una pipe e il codice che ho usato è stato quello pubblicato da t.888

      transform(obj: {[key: string]: any}, arg: string) { if (!obj) return undefined; return arg === 'keyval' ? 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; 

    Onestamente penso che una delle cose che mi stava facendo era la mancanza di gestione degli errori, aggiungendo la chiamata ‘return undefined’ credo che ora stiamo permettendo che i dati non previsti siano inviati alla pipe, cosa che ovviamente stava accadendo nel mio caso .

    se non vuoi trattare argomenti alla pipe (e guarda non credo sia necessario nella maggior parte dei casi) puoi semplicemente restituire quanto segue

      if (!obj) return undefined; return Object.keys(obj); 

    Alcune note sulla creazione di pipe, pagine o componenti che utilizzano quella pipe

    sto ricevendo errori su ‘name_of_my_pipe’ non trovato

    Utilizzare il comando ‘ionic generate pipe’ dalla CLI per assicurarsi che i moduli pipe siano creati e referenziati correttamente. assicurati di aggiungere quanto segue alla pagina mypage.module.ts.

     import { PipesModule } from '…/…/pipes/pipes.module'; 

    (non sono sicuro che questo cambi se hai anche il tuo custom_module, potresti anche aver bisogno di aggiungerlo a custommodule.module.ts)

    se hai usato il comando ‘ionic generate page’ per creare la tua pagina, ma decidi di usare quella pagina come pagina principale, ricorda di rimuovere il riferimento alla pagina da app.module.ts (ecco un’altra risposta che ho postato che trattava di quell’https: / /forum.ionicframework.com/t/solved-pipe-not-found-in-custom-component/95179/13?u=dreaser

    Nella mia ricerca di risposte là dove un certo numero di modi per visualizzare i dati nel file html, e non capisco abbastanza per spiegare le differenze. Potresti trovare preferibile utilizzarne uno su un altro in determinati scenari.

           

    Tuttavia, ciò che ha funzionato mi ha permesso di visualizzare sia il valore che la chiave:

        

    Key Value = {{posts[myPost]}}

    Key Name = {{myPost}}

    per rendere la chiamata API sembra che tu abbia bisogno di importare HttpModule in app.module.ts

     import { HttpModule } from '@angular/http'; . . imports: [ BrowserModule, HttpModule, 

    e hai bisogno di Http nella pagina da cui effettui la chiamata

     import {Http} from '@angular/http'; 

    Quando si effettua la chiamata API, sembra che si sia in grado di ottenere i dati dei bambini (gli oggetti o gli array all’interno dell’array) in 2 modi diversi, o sembrano funzionare

    sia durante la chiamata

     this.http.get('https://SomeWebsiteWithAPI').map(res => res.json().anyChildren.OrSubChildren).subscribe( myData => { 

    o quando assegni i dati alla tua variabile locale

     posts: Array; this.posts = myData['anyChildren']; 

    (non sono sicuro se quella variabile debba essere una stringa di array, ma questo è quello che ho adesso. Potrebbe funzionare come una variabile più generica)

    Infine, non è stato necessario utilizzare la libreria JSON incorporata, tuttavia è ansible trovare queste 2 chiamate a portata di mano per la conversione da un object a una stringa e viceversa

      var stringifiedData = JSON.stringify(this.movies); console.log("**mResults in Stringify"); console.log(stringifiedData); var mResults = JSON.parse(stringifiedData); console.log("**mResults in a JSON"); console.log(mResults); 

    Spero che questa raccolta di informazioni aiuti qualcuno a uscire.

    Fino ad ora la risposta migliore / più breve che ho trovato è (senza alcun filtro pipe o funzione personalizzata dal lato componente)

    Lato componente:

     objectKeys = Object.keys; 

    Lato modello:

     
    Key: {{key}}
    {{ obj.title }} {{ obj.desc }}

    DEMO DI LAVORO

    In JavaScript questo si tradurrà in un object che con i dati potrebbe apparire come questo

    Le interfacce in TypeScript sono un costrutto di sviluppo temporale (esclusivamente per gli strumenti … 0 impatto di runtime). Dovresti scrivere lo stesso TypeScript del tuo JavaScript.

    Il dizionario è un object, non un array. Credo che ng-repeat richieda un array in Angular 2.

    La soluzione più semplice sarebbe creare una pipe / filter che converta l’object in un array al volo. Detto questo, probabilmente vorrai usare un array come dice @basarat.

    Se hai es6-shim o il tuo target es6 , puoi usare ES6 Map per farlo.

     var myDict = new Map(); myDict.set('key1','value1'); myDict.set('key2','value2'); 
    key:{{keyVal[0]}}, val:{{keyVal[1]}}

    Definire MapValuesPipe e implementare PipeTransform :

     import {Pipe, PipeTransform} from '@angular/core'; @Pipe({name: 'mapValuesPipe'}) export class MapValuesPipe implements PipeTransform { transform(value: any, args?: any[]): Object[] { let mArray: value.forEach((key, val) => { mArray.push({ mKey: key, mValue: val }); }); return mArray; } } 

    Aggiungi la tua pipa nel modulo tubi. Questo è importante se è necessario utilizzare la stessa pipa in più di un componente :

     @NgModule({ imports: [ CommonModule ], exports: [ ... MapValuesPipe ], declarations: [..., MapValuesPipe, ...] }) export class PipesAggrModule {} 

    Quindi usa semplicemente la pipe nel tuo html con *ngFor :

    Ricorda, dovrai dichiarare il tuo PipesModule nel componente in cui desideri utilizzare la pipe:

     @NgModule({ imports: [ CommonModule, PipesAggrModule ], ... } export class MyModule {}