* ngFor kullanarak erişim anahtarı ve nesnenin değeri


426

Biraz almak hakkında karıştı duyuyorum keyve valuekullanırken angular2 bir nesnenin *ngFornesne üzerinden yineleme için. Açısal 1.x'te bir sözdizimi olduğunu biliyorum

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

ama aynı şeyi açısal olarak nasıl yapacağımı bilmiyorum2. Benzer bir şeyi başarılı olmadan denedim:

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

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

İşte benim girişim ile bir plnkr: http://plnkr.co/edit/mIj619FncOpfdwrR0KeG?p=preview

Nasıl alabilirim key1ve key2kullanma dinamik olarak *ngFor? Kapsamlı bir şekilde aradıktan sonra, boru kullanma fikrini buldum, ancak nasıl yapılacağını bilmiyorum. Aynı şeyi açısal2'de yapmak için dahili bir boru var mı?


2
Şu anda key, valueaçısal2'de çift tür sözdizimi desteklenmiyor ngFor, bu cevaba
Pankaj Parkar

@PankajParkar evet zaten bu cevabı okudum. Şimdilik alternatif var mı?
Pardeep Jain

@Pradeep Bunun için başka bir yol düşünmüyorum, bunun için kendi yolunu yaratmalısın Pipe..
Pankaj Parkar

hmm ama nasıl aynı boru oluşturmak için hiçbir fikrim yok.
Pardeep Jain

@ Referans için size verdiğim ticaret cevabı bu uygulamaya sahiptir. Çalışmalılar ..
Pankaj Parkar

Yanıtlar:


399

Var Object.keysşablonda erişilebilir ve kullanmak *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(){}
}


25
Bu daha iyi ve daha verimli bir çözümdür
Aous1000

1
@ tomtastico Bunu bir 3B dizi için nasıl görüntülersiniz? Örneğin {"1": {"1.1": ["1.1.1", "1.1.2"]}}. Ve sonra 3 ngFor's'un iç içe geçmesi
Frank

@Frank az önce kendin söyledin. S yuvalayın *ngFor. İlk iki kullanarak objectKeys, en içte gerek yok (sadece bir dizi olduğu için).
tomtastico

1
Muhteşem. ObjectKeys = Object.keys ayarı, bir nesnenin HTML'den uzunluğunu kontrol edebildiğimi gördüğüm en basit yöntemdir.
JAC

394

Angular Team'in (v6.1.0) en son sürümünde olduğu gibi , Angular Team, açısal paket modülünde keyvaluenesneler, haritalar ve diziler arasında yineleme yapmanıza yardımcı olmak için boru olarak adlandırılan aynı yeni boru ekledi common. Örneğin -

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

Çatallı Çalışma Örneği

daha yararlı bilgiler için buradan kontrol edin -

Angular v5 veya daha düşük bir sürümünü kullanıyorsanız veya boru kullanarak ulaşmak istiyorsanız bu cevabı takip edin


1
lol Ben sadece bu boru erişmek için bir ng6 güncelleme yapmak zorunda - harika şeyler - thx
danday74

36
Özel bir karşılaştırıcı kullanarak orijinal anahtar sırasını koruyabilirsiniz: *ngFor="let item of testObject | keyvalue:keepOriginalOrder" ve sınıfınızda şunları tanımlayın:public keepOriginalOrder = (a, b) => a.key
mike-shtil

2
public keepOriginalOrder = (a, b) => bunun için a.key thx bir sürü
Kumaresan Perumal

1
bu cevap olmalı - açısal 7 üzerinde iyi çalışıyor
calios

1
İnanılmaz bu ilk sürümden beri orada değildi
Carlos Pinzón

227

Her öğenin anahtar listesini döndürmek için özel bir kanal oluşturabilirsiniz. Bunun gibi bir şey:

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

ve şu şekilde kullanın:

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

Düzenle

Hem anahtar hem de değer içeren bir girdi de döndürebilirsiniz:

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

ve şu şekilde kullanın:

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

1
eksik kapanış braketini not edinkeys.push({key: key, value: value[key]);
Marton Pallagi

49
Aslında herkesin *ngForifade içinde koleksiyonlar oluşturmak için pipo kullanmasını önermiyorum . Büyük performans darboğazı oluşturur, çünkü değişiklik dedektörü değişiklikleri her kontrol ettiğinde koleksiyonu oluşturması gerekir.
martin

3
Çözüm için teşekkürler ... sorun, nesne her değiştiğinde borunun güncellenmemesi. Ben eklerseniz pure:falseborusuna, çok verimsiz hale gelir. Nesneyi her değiştirdiğimde (öğeyi kaldır) boruyu manuel olarak güncellemek için bir çözümünüz var mı?
ncohen

4
Cevap biraz modası geçmiş. * NgFor = "# içerik girişi | anahtarları" satırı düzgün çalışmıyor ve for ... in döngüsü daha iyi "için (Object.keys (değer) const anahtarı))" olarak değiştirildi
Experimenter

2
@RachChen Şablonlarda değil: common: NgFor has been removed as it was deprecated since v4. Use NgForOf instead. This does not impact the use of*ngFor in your templates.( jaxenter.com/road-to-angular-5-133253.html )
mwld

49

Güncelleme

In 6.1.0-beta.1 KeyValuePipe tanıtıldı https://github.com/angular/angular/pull/24319

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

Plunker Örneği

Önceki versiyon

Başka bir yaklaşım, aşağıdaki NgForIngibi kullanılacak bir yönerge oluşturmaktır :

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

Plunker Örneği

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

43

Açısal 6.1'den , anahtar değer borusunu kullanabilirsiniz :

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

Ancak, sonuç listesini anahtar değerine göre sıralamak sakıncalıdır. Tarafsız bir şeye ihtiyacınız varsa:

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

Pure: false pipe niteliğini belirtmeyi unutmayın . Bu durumda, giriş referansı değişmemiş olsa bile, boru her değişiklik algılama döngüsünde çağrılır (bir nesneye özellikler eklediğinizde de durum böyle olur).


Yukarıda aynı cevabı zaten paylaşmış stackoverflow.com/a/51491848/5043867
Pardeep Jain

26

@ Thierry'nin cevabının örnekle detaylandırılması.

key and value* NgFor döngüsünden almak için dahili bir boru veya yöntem yoktur . bu yüzden aynı için özel boru oluşturmak zorundayız. Thierry'nin dediği gibi burada kod ile cevap.

** Pipe sınıfı, bir girdi değeri ve isteğe bağlı parametre dizeleri dizisi alan ve dönüştürülen değeri döndüren PipeTransform arabiriminin dönüştürme yöntemini uygular.

** Dönüştürme yöntemi bir boru için gereklidir. PipeTransform arayüzü bu yöntemi tanımlar ve hem takımlara hem de derleyiciye rehberlik eder. İsteğe bağlıdır; Açısal, dönüştürme yöntemine bakmaksızın bakar ve yürütür. Boru ile ilgili daha fazla bilgi için buraya bakın

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

ve HTML kısmı:

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

Çalışma Plnkr http://plnkr.co/edit/50LlK0k6OnMnkc2kNHM2?p=preview

RC'ye güncelleme

burada kullanıcı6123723 tarafından önerildiği gibi (teşekkürler) burada güncelleme.

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

Bunun güncellenmesi gerekiyor: İşte ifadelerin içine "#" aldığım uyarı kaldırıldı. Bunun yerine "let" kullanın! ("</li> -> <ul * ngIf =" demo "> <li [HATA ->] * ngFor = '# demo | anahtarların anahtarı'> Anahtar: {{key.key}}, değer: { {key.value}} </li> "): Bileşenim @ 56: 6
user6123723

Bunun yeni olup olmadığından emin değilim, ancak dokümanlardan alıntı yapmak için:> Borumuzu AppModule'un bildirim dizisine eklemeliyiz.
Akzidenzgrotesk

18

@Marton , borunun her değişiklik tespiti için yeni bir koleksiyon oluşturduğu gerekçesiyle kabul edilen cevaba önemli bir itirazda bulundu . Bunun yerine, görünümü aşağıdaki gibi kullanabileceğiniz bir dizi yardımcı program işlevi sağlayan bir HtmlService oluştururdum:

@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...
}

2
ve bu sadece Object.keys(...)* ngFor'dan daha iyi nasıl ?
Simon_Weaver

8
Çünkü atacak TypeError: Cannot read property 'keys' of undefined. Şablonda desteklenmiyor gibi görünüyor.
Stephen Paul

1
Bu bir çözüm olarak çok iyi çalışır ve yukarıda belirtilen performans sorunlarından kaçınır. stackoverflow.com/questions/35534959/…
J. Adam Connor

merhaba, bu b templateseçenekte değil, şablonun gerçek html kodunda kullanılabilir mi? teşekkürler
Scaramouche

16

Halihazırda Lodash kullanıyorsanız, hem anahtar hem de değer içeren bu basit yaklaşımı yapabilirsiniz:

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

Dizgi dosyasına şunu ekleyin:

import * as _ from 'lodash';

ve dışa aktarılan bileşene şunları ekleyin:

_: any = _;

üzgünüm ama böyle şeyler için Lodash gibi ekstra bir kitaplık kullanmaya gerek yok. neyse yeni yöntemler her zaman beklerim :)
Pardeep Jain

8

Boru için teşekkürler ama açısal 2 RC5 kullanmak önce bazı değişiklikler yapmak zorunda kaldı. Boru içe aktarma satırını değiştirdi ve ayrıca anahtar dizisi başlatma işlemine herhangi bir tür ekledi.

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

evet ithalat değiştirildi
Pardeep Jain

7

Buradaki cevapların hiçbiri benim için kutudan çıkmadı, benim için işe yarayan şey:

pipes/keys.tsİçeriklerle oluştur :

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

Ekle app.module.ts(Ana modülünüz):

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

ve modül bildirim dizinize şöyle bir şey ekleyin:

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

Ardından görünüm şablonunuzda şöyle bir şey kullanabilirsiniz:

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

Burada daha okumak istiyorsanız buldum iyi referanstır.


cevabınızla yukarıda verilen diğer cevapların (sadece pipo kullanarak) arasındaki farkın ne olduğunu öğrenebilir miyim? yukarıdakiyle aynı görünüyor
Pardeep Jain

1
Elbette 1. Yukarıdaki örneklerde * ngFor = "let giriş" yerine * ngFor = "# giriş" kullanılmıştır ve derleyicim # giriş sözdizimini kabul etmedi, referans # kullanmıyor. "let girdi (myData | keys)" daha iyi bir çözüm gibi görünüyor. 2. Benim derleyici örnek Boru Sınıfı ya da açık veri türleri eksik olduğu için doğrulamadı bu yüzden bunu ekledi. 3. Yukarıdaki örnekler, Borunun cevabımın yaptığı bir projeye nasıl entegre edileceğini göstermez, ana modüle almanız gerekir.
cjohansson

haha evet offcourese, çünkü cevap o zaman sözdizimi #vb. dahil olduğunda verildi . btw cevabınız da doğru değil şüphesiz
Pardeep Jain

6

Bunu diğer hoş borular arasında yapan gerçek bir kütüphane var. Buna ngx-borular denir .

Örneğin, anahtarlar borusu bir nesnenin anahtarlarını döndürür ve değerler borusu bir nesnenin değerlerini döndürür:

tuşları boru

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

değerleri boru

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

Kendi özel borunuzu oluşturmanıza gerek yok :)


2
iyi bir alternatif, ama şey, boru gibi basit bir kod parçası kullanarak bunu yapabilirsek, kodun basit olması için harici kütüphaneyi neden kullanmamızdır
Pardeep Jain 22:17

2
Hımm ... ama bir boru mu? Bu, paketinizdeki sadece bir satırdır. Kütüphaneyi içe aktardığınızda modülünüzde json ve iki satır daha bulunur. Öte yandan, özel bir borunun 10-20 satırlık kod içeren ayrı bir dosyaya ve ayrıca modülünüzdeki içe aktarma hatlarına ihtiyacı vardır. Ngx-pipe kullanımını projelerimizde çok kolay buluyoruz. Neden tekerleği yeniden keşfetmeliyiz? :)
RichieRock

evet şüphesiz, aslında bu bir fikir tabanlı, bu ikisi arasında seçim yapabilirsiniz, kimse yanlış bir yol.
Pardeep Jain

2
Unutmayın, eğer özel bir boru yazarsanız, o özel boruyu da test etmeniz gerekir . Bu, 10-20 satır boru kodu ve daha sonra boruyu test etmek için muhtemelen 20-40 satır test kodu.
danwellman

4

Kullanım endeksi:

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

Kullanımı:

{{key}} -> {{value}}

1
Bu benim için yeni bir şey, daha iyi Cevabınızla birlikte örnek ekleyebiliyorsanız :) Ayrıca bana aynı dokümantasyona da işaret edebilir misiniz?
Pardeep Jain

Nesnelerin türü nedir? Dizi veya Harita? Lütfen netleştirin. Şimdiden teşekkürler
Basil Mohammed

3

İşte basit çözüm

Bunun için daktilo yineleyicileri kullanabilirsiniz

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

demo türünü dizi olarak değiştirin veya nesneniz üzerinde yineleyin ve başka bir diziye aktarın

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

ve html'den:

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

Bu uygun bir yöntem değildir, bu herkes tarafından kolayca yapılabilir.
Pardeep Jain

1

Object.keys bu soruna en iyi çözüm olduğunu düşünüyorum. Bu yanıta rastlayan ve Object.keys'in neden uyarıcı bir masal yerine ['key1', 'key2'] yerine ['0', '1'] verdiğini bulmaya çalışan herkes için - " ve "in":

Zaten Object.keys, buna benzer bir şey kullanıyordum:

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

Ancak, bunun yerine

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

Yanlışlıkla yazmıştım

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

herhangi bir hata olmadan mükemmel "çalıştı" ve döndü

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

Bu bana yaklaşık 2 saat googling ve lanetleme maliyeti ..

(alnı tokatlar)


1

bunu deneyerek dinamik nesnenin anahtarını alabilirsiniz

myObj['key']

0

Şimdilik böyle yapmak zorundasınız, ateş tabanından aldığınız nesneyi dönüştürmek istemediğiniz için çok verimli değilim.

    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;

    });
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.