Cara melakukan iterasi menggunakan ngFor loop Map yang berisi kunci sebagai string dan nilai sebagai iterasi peta

109

Saya baru mengenal sudut 5 dan mencoba mengulang peta yang berisi peta lain dalam skrip ketikan. Cara mengiterasi di bawah peta semacam ini dengan sudut di bawah ini adalah kode untuk komponen:

import { Component, OnInit} from '@angular/core';

@Component({
  selector: 'app-map',
  templateUrl: './map.component.html',
  styleUrls: ['./map.component.css']
})
export class MapComponent implements OnInit {
  map = new Map<String, Map<String,String>>();
  map1 = new Map<String, String>();

  constructor() { 


  }

  ngOnInit() {
    this.map1.set("sss","sss");
    this.map1.set("aaa","sss");
    this.map1.set("sass","sss");
    this.map1.set("xxx","sss");
    this.map1.set("ss","sss");


    this.map1.forEach((value: string, key: string) => {
      console.log(key, value);

    });


    this.map.set("yoyoy",this.map1);

  }



}

dan template html-nya adalah:

<ul>
  <li *ngFor="let recipient of map.keys()">
    {{recipient}}
   </li>


</ul>

<div>{{map.size}}</div>

kesalahan runtime

Feroz Siddiqui
sumber
apa solusinya saya tidak ingin mengubah peta saya menjadi array
Feroz Siddiqui
terima kasih bekerja dengan sangat baik
Feroz Siddiqui

Jawaban:

246

Untuk Angular 6.1+ , Anda dapat menggunakan pipa default keyvalue( Lakukan review dan upvote juga ):

<ul>
    <li *ngFor="let recipient of map | keyvalue">
        {{recipient.key}} --> {{recipient.value}}
    </li>
</ul>

DEMO KERJA


Untuk versi sebelumnya:

Salah satu solusi sederhana untuk ini adalah mengonversi peta menjadi array: Array.from

Komponen Sisi:

map = new Map<String, String>();

constructor(){
    this.map.set("sss","sss");
    this.map.set("aaa","sss");
    this.map.set("sass","sss");
    this.map.set("xxx","sss");
    this.map.set("ss","sss");
    this.map.forEach((value: string, key: string) => {
        console.log(key, value);
    });
}

getKeys(map){
    return Array.from(map.keys());
}

Sisi Template:

<ul>
  <li *ngFor="let recipient of getKeys(map)">
    {{recipient}}
   </li>
</ul>

DEMO KERJA

Vivek Doshi
sumber
1
if map = new Map <String, Map <String, String >> (); bagaimana cara kerjanya?
Feroz Siddiqui
@FerozSiddiqui, saya telah memperbarui jawabannya, dan saya pikir itu akan berfungsi untuk semua level bersarang.
Vivek Doshi
kami kehilangan semua fitur Peta jika akhirnya kami mengubahnya menjadi Array. lalu apa manfaat dari Map?
diEcho
1
@ pro.mean, kita mengonversi hanya karena kita ingin mengulangnya melalui template bersudut karena ingin beberapa iterable untuk diulang. dan Anda masih memiliki objek asli yang maptersedia, Anda dapat menggunakannya untuk menggunakan semua manfaat Peta
Vivek Doshi
1
@ pro.mean, kami telah mengonversi hanya untuk menampilkannya di sisi template, tetapi Anda masih memiliki objek Map yang dapat Anda gunakan di sisi komponen Anda. Anda bisa bertanya ke OP why he needed this kind of requirement, dia bisa menjelaskan lebih baik :)
Vivek Doshi
48

Jika Anda menggunakan Angular 6.1 atau yang lebih baru, cara yang paling nyaman adalah menggunakan KeyValuePipe

   @Component({
      selector: 'keyvalue-pipe',
      template: `<span>
        <p>Object</p>
        <div *ngFor="let item of object | keyvalue">
          {{item.key}}:{{item.value}}
        </div>
        <p>Map</p>
        <div *ngFor="let item of map | keyvalue">
          {{item.key}}:{{item.value}}
        </div>
      </span>`
    })
    export class KeyValuePipeComponent {
      object: Record<number, string> = {2: 'foo', 1: 'bar'};
      map = new Map([[2, 'foo'], [1, 'bar']]);
    }
Londeren
sumber
3
Mudah-mudahan orang menggulir dan melihat jawaban ini, karena saya akan melakukan refactor sampai saya melihat pipa out-of-the-box ini tersedia untuk maptipe saya yang menangani penggunaannya dengan*ngFor
atconway
2
tampaknya, keyvalue tidak menyimpan penyortiran awal peta :-(, Anda perlu menambahkan fungsi pembanding untuk memperbaikinya
Konstantin Vahrushev
1
Ini benar. Dan ini masalahnya github.com/angular/angular/issues/31420
Londeren
24

Sunting

Untuk angular 6.1 dan yang lebih baru, gunakan KeyValuePipe seperti yang disarankan oleh Londeren.

Untuk sudut 6.0 dan lebih tua

Untuk mempermudah, Anda bisa membuat pipa.

import {Pipe, PipeTransform} from '@angular/core';

@Pipe({name: 'getValues'})
export class GetValuesPipe implements PipeTransform {
    transform(map: Map<any, any>): any[] {
        let ret = [];

        map.forEach((val, key) => {
            ret.push({
                key: key,
                val: val
            });
        });

        return ret;
    }
}

 <li *ngFor="let recipient of map |getValues">

Karena murni, itu tidak akan dipicu pada setiap deteksi perubahan, tetapi hanya jika referensi ke mapvariabel berubah

Demo Stackblitz

David
sumber
Saya pikir pipa Anda akan diperiksa untuk perubahan dan melakukan iterasi penuh pada setiap siklus deteksi perubahan karena tidak "murni". Tidak menjatuhkan suara tapi mungkin itu sebabnya?
Drenai
5
@Ryan Pipes murni secara default. Jika Anda menambahkan console.log di pipa, Anda akan melihat bahwa itu tidak mendapatkan panggilan berkali-kali. Tapi metode komponen dalam solusi yang diterima tidak ...
David
1
Saya mendapatkannya mundur! Terima kasih atas perhatiannya
Drenai
10

Ini karena map.keys()mengembalikan iterator. *ngFordapat bekerja dengan iterator, tetapi map.keys()akan dipanggil pada setiap siklus deteksi perubahan, sehingga menghasilkan referensi baru ke larik, menghasilkan kesalahan yang Anda lihat. Ngomong-ngomong, ini tidak selalu merupakan kesalahan seperti yang biasanya Anda pikirkan; bahkan mungkin tidak merusak fungsionalitas Anda, tetapi menunjukkan bahwa Anda memiliki model data yang tampaknya berperilaku gila - berubah lebih cepat daripada detektor perubahan memeriksa nilainya.

Jika Anda tidak ingin mengubah peta menjadi array dalam komponen Anda, Anda dapat menggunakan pipa yang disarankan di komentar. Sepertinya tidak ada solusi lain.

PS Kesalahan ini tidak akan ditampilkan dalam mode produksi, karena ini lebih seperti peringatan yang sangat ketat, daripada kesalahan sebenarnya, tetapi tetap saja, ini bukan ide yang baik untuk membiarkannya.

Armen Vardanyan
sumber
1

Seperti yang telah disebutkan orang dalam komentar keyvalue pipe tidak mempertahankan urutan penyisipan (yang merupakan tujuan utama dari Map).

Bagaimanapun, terlihat seperti jika Anda memiliki objek Map dan ingin mempertahankan urutannya, cara terbersih untuk melakukannya adalah fungsi entries ():

<ul>
    <li *ngFor="let item of map.entries()">
        <span>key: {{item[0]}}</span>
        <span>value: {{item[1]}}</span>
    </li>
</ul>
Wildhammer
sumber
Silakan lihat github.com/angular/angular/issues/31420#issuecomment-635377113 mengapa Anda harus menghindari penggunaan .entries ()
Florian
1

Kode di bawah ini berguna untuk ditampilkan dalam urutan penyisipan peta .

<ul>
    <li *ngFor="let recipient of map | keyvalue: asIsOrder">
        {{recipient.key}} --> {{recipient.value}}
    </li>
</ul>

File .ts tambahkan kode di bawah ini.

asIsOrder(a, b) {
    return 1;
}
Shakthifuture
sumber