Ulangi objek dalam Angular

130

Saya mencoba melakukan beberapa hal dalam Angular 2 Alpha 28, dan saya mengalami masalah dengan kamus dan NgFor.

Saya memiliki antarmuka dalam TypeScript yang terlihat seperti ini:

interface Dictionary {
    [ index: string ]: string
}

Dalam JavaScript ini akan menerjemahkan ke objek yang dengan data mungkin terlihat seperti ini:

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

Saya ingin mengulangi ini dan mencoba ini:

<div *ngFor="(#key, #value) of myDict">{{key}}:{{value}}</div>

Tetapi tidak berhasil, tidak ada yang di bawah ini yang berfungsi:

<div *ngFor="#value of myDict">{{value}}</div>
<div *ngFor="#value of myDict #key=index">{{key}}:{{value}}</div>

Dalam semua kasus, saya mendapatkan kesalahan seperti "Token tak terduga" atau "Tidak dapat menemukan objek pendukung pipa 'iterableDiff'"

Apa yang kulewatkan di sini? Apakah ini tidak mungkin lagi? (Sintaks pertama bekerja di Angular 1.x) atau apakah sintaks berbeda untuk iterasi pada objek?

Rickard Staaf
sumber
Apa itu "kamus"? Saya belum pernah melihat atau mendengar istilah itu dalam konteks JavaScript, Angular, atau TypeScript. Y
Kamus berarti peta saya pikir, istilah ini tidak digunakan sama sekali dalam konteks JS tetapi dalam Python atau Ruby itu digunakan.
Cesar Jr Rodriguez
2
Saya pikir jawaban @bersling sekarang adalah jawaban yang benar untuk pertanyaan ini.
Joshua Kissoon
1
Harap tandai jawaban yang benar dengan lebih baik. bersling benar
diaktifkanecay

Jawaban:

86

Tampaknya mereka tidak ingin mendukung sintaks dari ng1.

Menurut Miško Hevery ( referensi ):

Peta tidak memiliki pesanan dalam kunci dan karenanya iterasi tidak dapat diprediksi. Ini didukung di ng1, tapi kami pikir itu kesalahan dan tidak akan didukung di NG2

Rencananya adalah memiliki pipa mapToIterable

<div *ngFor"var item of map | mapToIterable">

Jadi untuk beralih pada objek Anda, Anda perlu menggunakan "pipa". Saat ini tidak ada pipa yang diimplementasikan yang melakukan itu.

Sebagai solusinya, berikut adalah contoh kecil yang beralih di atas kunci:

Komponen:

import {Component} from 'angular2/core';

@Component({
  selector: 'component',
  templateUrl: `
       <ul>
       <li *ngFor="#key of keys();">{{key}}:{{myDict[key]}}</li>
       </ul>
  `
})
export class Home {
  myDict : Dictionary;
  constructor() {
    this.myDict = {'key1':'value1','key2':'value2'};
  }

  keys() : Array<string> {
    return Object.keys(this.myDict);
  }
}

interface Dictionary {
    [ index: string ]: string
}
Jesse Bagus
sumber
1
saya mencoba yang sama pada objek dengan keyas numberdan valueas stringtetapi sudut adalah melempar kesalahan expression has changed after it was checked? mengapa begitu ide?
Pardeep Jain
Ya ini juga terjadi pada saya. Dan sama jika saya menggunakan solusi @ obsur juga.
user2294382
1
Silakan lihat jawaban bersling karena ada solusi sepele pada sudut 7 terbaru
Activedecay
156

6.1.1+ Angular Jawab

Gunakan built-in keyvalue-pipe seperti ini:

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

atau seperti ini:

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

di mana mySortingFunctiondi .tsfile Anda , misalnya:

mySortingFunction = (a, b) => {
  return a.key > b.key ? -1 : 1;
}

Stackblitz: https://stackblitz.com/edit/angular-iterate-key-value

Anda tidak perlu mendaftarkan ini dalam modul apa pun, karena pipa Angular bekerja di luar kotak dalam template apa pun.

Ini juga berfungsi untuk Javascript-Maps .

bersling
sumber
Anda harus menambahkan implements PipeTransformdefinisi kelas (lihat angular.io/guide/pipes#custom-pipes )
toioski
1
@ toioski terima kasih, saya telah menambahkannya dan memperbarui ke sintaks baru for for.
bersling
Jawaban yang bagus, gunakan ini untuk ngFor Kamus saya. Saya harus melakukan keyValuePair.val [0] meskipun nilai saya berakhir [{}] dan bukan {}
jhhoff02
1
Apakah ada keuntungan untuk ini selain return Object.keys(dict).map(key => ({key, val: dict[key]}))?
Justin Morgan
Saya tidak melihat, sebenarnya saya akan menggunakan cara Anda!
bersling
72

coba gunakan pipa ini

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

<div *ngFor="#value of object | values"> </div>
tidak jelas
sumber
5
Cemerlang, dan jika saya ingin menyimpan referensi ke kunci saya hanya akan memetakan objek dengan kedua kunci dan nilai sebagai gantinya. Saya berharap saya dapat menandai beberapa jawaban sebagai jawaban yang diterima, karena ini adalah solusi untuk masalah saya sementara jawaban yang ditandai adalah jawaban untuk pertanyaan saya.
Rickard Staaf
1
@obscur - Jika saya melakukan hal di atas sekarang, saya mendapatkan kesalahan "ekspresi telah berubah setelah diperiksa" menggunakan angular2.beta.0.0. Adakah pikiran?
user2294382
Itu karena murni: salah membutuhkan perubahan deteksi Strategi untuk diinjeksi
Judson Terrell
1
Mengapa mengaturnya menjadi tidak murni?
tom10271
Ini bekerja dengan baik untuk saya. Satu-satunya hal adalah saya tidak dapat menggunakan # di ngFor. Digunakan sebagai gantinya.
MartinJH
19

Selain jawaban @ obscur, berikut adalah contoh bagaimana Anda dapat mengakses keydan valuedari @View.

Pipa:

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

}

Melihat:

<li *ngFor="let u of myObject | 
keyValueFilter">First Name: {{u.key}} <br> Last Name: {{u.value}}</li>

Jadi jika objeknya terlihat seperti:

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

Hasil yang dihasilkan adalah:

Nama depan: Daario
Nama Belakang: Naharis

Nama depan: Victarion
Nama Belakang: Greyjoy

Nama depan: Quentyn
Nama Belakang: Ball

SimonHawesome
sumber
2
hanya satu hal lagi yang perlu Anda ubah View: as <li *ngFor="let u of myObject | keyValueFilter">First Name: {{u.key}} <br> Last Name: {{u.value}}</li>. +1 dari saya.
sib10
Kode di dalam fungsi peta Anda dapat disederhanakan sebagai: return { 'key' : key, 'value' : value[key] };
Makotosan
17

Diperbarui: Angular sekarang menyediakan pipa untuk melompat melalui Objek json melalui keyvalue:

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

DEMO KERJA , dan untuk lebih detail Baca


Sebelumnya (Untuk Versi Lama): Sampai sekarang jawaban terbaik / terpendek yang saya temukan adalah (Tanpa Filter Pipa atau fungsi Kustom dari Sisi Komponen)

Sisi komponen:

objectKeys = Object.keys;

Sisi templat:

<div *ngFor='let key of objectKeys(jsonObj)'>
   Key: {{key}}

    <div *ngFor='let obj of jsonObj[key]'>
        {{ obj.title }}
        {{ obj.desc }}
    </div>

</div>

DEMO KERJA

Vivek Doshi
sumber
1
let item of myDict | keyvalueini menyelesaikan masalah saya.
Silambarasan RD
13

Menambahkan ke jawaban SimonHawesome yang luar biasa . Saya telah membuat versi ringkas yang menggunakan beberapa fitur naskah baru. Saya menyadari bahwa versi SimonHawesome sengaja dibuat untuk menjelaskan rincian yang mendasarinya. Saya juga telah menambahkan pemeriksaan awal agar pipa berfungsi untuk nilai falsy . Misal, jika peta itunull .

Perhatikan bahwa menggunakan transformasi iterator (seperti yang dilakukan di sini) dapat lebih efisien karena kita tidak perlu mengalokasikan memori untuk array sementara (seperti yang dilakukan dalam beberapa jawaban lain).

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] }));
    }
}
Frederik Aalund
sumber
3
suka utas ini, dengan satu komentar membangun yang lain! Saya akan menulis hal yang sama ketika saya melihat kode Anda
David
3
satu-satunya hal dalam solusi ini: itu harus diterapkanPipeTransform
iRaS
@ iRaS Poin bagus. Saya telah memperbarui jawaban saya. Saya juga mengembalikan undefined bukan null.
Frederik Aalund
9

Berikut variasi pada beberapa jawaban di atas yang mendukung banyak transformasi (keyval, key, value):

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

Pemakaian

map = {
    'a': 'aee',
    'b': 'bee',
    'c': 'see'
}

<div *ngFor="let o of map | mapToIterable">{{o.key}}: {{o.value}}</div>
  <div>a: aee</div>
  <div>b: bee</div>
  <div>c: see</div>

<div *ngFor="let o of map | mapToIterable:'keyval'">{{o.key}}: {{o.value}}</div>
  <div>a: aee</div>
  <div>b: bee</div>
  <div>c: see</div>

<div *ngFor="let k of map | mapToIterable:'key'">{{k}}</div>
  <div>a</div>
  <div>b</div>
  <div>c</div>

<div *ngFor="let v of map | mapToIterable:'value'">{{v}}</div>
  <div>aee</div>
  <div>bee</div>
  <div>see</div>
t.888
sumber
1
pure: falsesangat penting untuk refleksi instan.
Fırat KÜÇÜK
4

Saya memiliki masalah serupa, membuat sesuatu untuk objek dan 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:
 * 
 *  <div *ngFor="#keyValuePair of someObject | mapToIterable">
 *    key {{keyValuePair.key}} and value {{keyValuePair.value}}
 *  </div>
 * 
 */
@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;
  }
}

amcdnl
sumber
1
Ini berfungsi baik, kecuali bahwa dalam TypeScript Anda harus menambahkan implements PipeTransformdefinisi kelas
GeorgDangl
3

Angular 2.x && Angular 4.x tidak mendukung ini di luar kotak

Anda dapat menggunakan dua pipa ini untuk beralih dengan kunci atau nilai .

Pipa kunci:

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

Nilai pipa:

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

Cara Penggunaan:

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

<div *ngFor="let key of data | keys"></div>
<div *ngFor="let value of data | values"></div>
MK
sumber
2

Jika seseorang bertanya-tanya bagaimana cara bekerja dengan objek multidimensi, inilah solusinya.

mari kita asumsikan kita memiliki objek berikut dalam layanan

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

dalam komponen tambahkan fungsi berikut

challenges;

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

Akhirnya dalam pandangan lakukan mengikuti

<div *ngFor="#key of keys();">
    <h4 class="heading">{{challenges[key].title}}</h4>
    <p class="description">{{challenges[key].description}}</p>
</div>
Chynajai Sydykov
sumber
2

Saya telah merobek rambut saya dengan mencoba mengurai dan menggunakan data yang dikembalikan dari permintaan JSON / panggilan api. Saya tidak yakin persis di mana saya salah, saya merasa seperti saya telah melingkari jawaban selama berhari-hari, mengejar berbagai kode kesalahan seperti:

"Tidak dapat menemukan objek pendukung pipa 'iterableDiff'"

"Generic TYpe Array membutuhkan satu argumen"

Kesalahan JSON parsing, dan saya yakin orang lain

Saya berasumsi saya baru saja salah kombinasi perbaikan.

Jadi, inilah sedikit ringkasan tentang gotcha dan hal-hal yang harus dicari.

Pertama-tama periksa hasil panggilan api Anda, hasil Anda mungkin dalam bentuk objek, array, atau array objek.

saya tidak akan membahasnya terlalu banyak, cukup untuk mengatakan Kesalahan asli OP karena tidak dapat diubah umumnya disebabkan oleh Anda mencoba untuk mengulangi objek, bukan Array.

Inilah beberapa hasil debug saya yang menunjukkan variabel array dan objek

Jadi karena kami umumnya ingin mengulangi hasil JSON kami, kami perlu memastikannya dalam bentuk Array. Saya mencoba banyak contoh, dan mungkin mengetahui apa yang saya tahu sekarang beberapa dari mereka sebenarnya akan bekerja, tetapi pendekatan yang saya lakukan adalah dengan mengimplementasikan pipa dan kode yang saya gunakan adalah yang diposting oleh 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;

Jujur saya pikir salah satu hal yang membuat saya kurang penanganan kesalahan, dengan menambahkan panggilan 'kembali tidak terdefinisi' saya percaya kita sekarang memungkinkan data yang tidak diharapkan untuk dikirim ke pipa, yang jelas terjadi dalam kasus saya .

jika Anda tidak ingin berurusan dengan argumen ke pipa (dan lihat saya pikir itu tidak perlu dalam kebanyakan kasus) Anda bisa mengembalikan yang berikut ini

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

Beberapa Catatan tentang membuat pipa dan halaman atau komponen Anda yang menggunakan pipa itu

adalah saya menerima kesalahan tentang 'name_of_my_pipe' tidak ditemukan

Gunakan perintah 'menghasilkan pipa ion' dari CLI untuk memastikan modul pipa.ts dibuat dan dirujuk dengan benar. pastikan Anda menambahkan yang berikut ke halaman mypage.module.ts.

import { PipesModule } from ‘…/…/pipes/pipes.module’;

(tidak yakin apakah ini berubah jika Anda juga memiliki custom_module Anda sendiri, Anda mungkin perlu menambahkannya ke custommodule.module.ts)

jika Anda menggunakan perintah 'menghasilkan halaman ion' untuk membuat halaman Anda, tetapi memutuskan untuk menggunakan halaman itu sebagai halaman utama Anda, ingatlah untuk menghapus referensi halaman dari app.module.ts (inilah jawaban lain yang saya posting berurusan dengan itu https: / /forum.ionicframework.com/t/solved-pipe-not-found-in-custom-component/95179/13?u=dreaser

Dalam mencari jawaban ada beberapa cara untuk menampilkan data dalam file html, dan saya tidak cukup mengerti untuk menjelaskan perbedaannya. Anda mungkin merasa lebih baik untuk menggunakan satu sama lain dalam skenario tertentu.

            <ion-item *ngFor="let myPost of posts">
                  <img src="https://somwhereOnTheInternet/{{myPost.ImageUrl}}"/>
                  <img src="https://somwhereOnTheInternet/{{posts[myPost].ImageUrl}}"/>
                  <img [src]="'https://somwhereOnTheInternet/' + myPost.ImageUrl" />
            </ion-item>

Namun apa yang berhasil yang memungkinkan saya untuk menampilkan nilai dan kuncinya adalah sebagai berikut:

    <ion-list>  
      <ion-item *ngFor="let myPost of posts  | name_of_pip:'optional_Str_Varible'">

        <h2>Key Value = {{posts[myPost]}} 

        <h2>Key Name = {{myPost}} </h2>

      </ion-item>
   </ion-list>  

untuk membuat panggilan API sepertinya Anda perlu mengimpor HttpModule ke app.module.ts

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

dan Anda memerlukan Http di laman tempat Anda menelepon

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

Saat melakukan panggilan API, Anda tampaknya bisa mendapatkan data anak-anak (objek atau array dalam array) 2 cara berbeda, entah itu berfungsi

baik saat panggilan berlangsung

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

atau ketika Anda menetapkan data ke variabel lokal Anda

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

(tidak yakin apakah variabel itu perlu menjadi Array String, tapi itulah yang saya miliki saat ini. Mungkin berfungsi sebagai variabel yang lebih umum)

Dan catatan terakhir, itu tidak perlu untuk menggunakan perpustakaan JSON inbuilt namun Anda mungkin menemukan 2 panggilan ini berguna untuk mengkonversi dari objek ke string dan vica sebaliknya

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

        var mResults = JSON.parse(<string>stringifiedData);
        console.log("**mResults in a JSON");
        console.log(mResults);

Saya harap kompilasi informasi ini membantu seseorang.

Dreaser
sumber
2
//Get solution for ng-repeat    
//Add variable and assign with Object.key

    export class TestComponent implements OnInit{
      objectKeys = Object.keys;
      obj: object = {
        "test": "value"
        "test1": "value1"
        }
    }
    //HTML
      <div *ngFor="let key of objectKeys(obj)">
        <div>
          <div class="content">{{key}}</div>
          <div class="content">{{obj[key]}}</div>
        </div>
Rohit Jangid
sumber
1

Dalam JavaScript ini akan menerjemahkan ke objek yang dengan data mungkin terlihat seperti ini

Antarmuka dalam TypeScript adalah konstruksi waktu dev (murni untuk tooling ... 0 dampak runtime). Anda harus menulis TypeScript yang sama dengan JavaScript Anda.

basarat
sumber
itu tidak benar, sry. ketik skrip memaksa Anda untuk menulis kode bersih. itu jauh lebih mudah untuk kelas abstrak. yang Anda tidak punya. C ++ mengkompilasi ke beberapa asm - asm juga tidak memiliki kelas atau bahkan tipe, namun Anda menulis berbeda c ++ lalu kode asm Anda: P
YAMM
1

Kamus adalah objek, bukan array. Saya percaya ng-repeat membutuhkan array di Angular 2.

Solusi paling sederhana adalah dengan membuat pipa / filter yang mengubah objek menjadi array dengan cepat. Yang mengatakan, Anda mungkin ingin menggunakan array seperti kata @basarat.

Martin
sumber
1

Jika Anda memiliki es6-shimatau tsconfig.jsontarget es6Anda, Anda bisa menggunakan ES6 Map untuk membuatnya.

var myDict = new Map();
myDict.set('key1','value1');
myDict.set('key2','value2');

<div *ngFor="let keyVal of myDict.entries()">
    key:{{keyVal[0]}}, val:{{keyVal[1]}}
</div>
Bernyanyi
sumber
0

Tentukan MapValuesPipedan implementasikan 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;
    }
}

Tambahkan pipa Anda di modul pipa Anda. Ini penting jika Anda perlu menggunakan pipa yang sama di lebih dari satu komponen :

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

Maka cukup gunakan pipa di html Anda dengan *ngFor:

<tr *ngFor="let attribute of mMap | mapValuesPipe">

Ingat, Anda harus mendeklarasikan PipesModule Anda di komponen tempat Anda ingin menggunakan pipa:

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

Jadi saya akan mengimplementasikan fungsi pembantu saya sendiri, objLength (obj), yang mengembalikan hanya Object (obj) .keys.length. Tetapi kemudian ketika saya menambahkannya ke fungsi template * ngIf, IDE saya menyarankan objectKeys (). Saya mencobanya, dan berhasil. Setelah deklarasi, tampaknya ditawarkan oleh lib.es5.d.ts, jadi begitulah!

Inilah cara saya mengimplementasikannya (Saya memiliki objek khusus yang menggunakan kunci yang dihasilkan sisi server sebagai indeks untuk file yang saya unggah):

        <div *ngIf="fileList !== undefined && objectKeys(fileList).length > 0">
          <h6>Attached Files</h6>
          <table cellpadding="0" cellspacing="0">
            <tr *ngFor="let file of fileList | keyvalue">
              <td><a href="#">{{file.value['fileName']}}</a></td>
              <td class="actions">
                <a title="Delete File" (click)="deleteAFile(file.key);">
                </a>
              </td>
            </tr>
          </table>
        </div>
mausolos
sumber