Cách lặp bằng cách sử dụng ngFor loop Bản đồ chứa khóa dưới dạng chuỗi và các giá trị dưới dạng lặp bản đồ


104

Tôi mới làm quen với góc 5 và đang cố gắng lặp lại bản đồ có chứa một bản đồ khác trong kiểu chữ. Cách lặp lại bên dưới loại bản đồ này ở dạng góc dưới đây là mã cho thành phần:

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

  }



}

và html mẫu của nó là:

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


</ul>

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

lỗi runtime



giải pháp tôi không muốn chuyển đổi bản đồ của tôi để mảng là gì
Feroz Siddiqui


nhờ hoạt động rất tốt
Feroz Siddiqui

Câu trả lời:


234

Đối với Angular 6.1+ , bạn có thể sử dụng đường dẫn mặc định keyvalue( Cũng có thể xem xét và ủng hộ ):

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

LÀM VIỆC DEMO


Đối với phiên bản trước:

Một giải pháp đơn giản cho việc này là chuyển đổi bản đồ thành mảng: Array.from

Mặt thành phần:

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

Mặt mẫu:

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

LÀM VIỆC DEMO


1
if map = new Map <String, Map <String, String >> (); nó làm việc như thế nào?
Feroz Siddiqui

@FerozSiddiqui, tôi đã cập nhật câu trả lời và tôi nghĩ rằng câu trả lời sẽ hoạt động cho bất kỳ cấp độ lồng nhau nào.
Vivek Doshi

chúng tôi đã mất tất cả tính năng Bản đồ nếu cuối cùng chúng tôi chuyển đổi nó thành Mảng. lợi ích của Bản đồ sau đó là gì?
diEcho

1
@ pro.mean, chúng tôi đang chuyển đổi chỉ vì chúng tôi muốn lặp qua nó qua mẫu góc cạnh vì nó muốn một số có thể lặp lại để lặp lại. và bạn vẫn có đối tượng ban đầu mapcó sẵn, bạn có thể sử dụng một để sử dụng tất cả các lợi ích của Bản đồ
Vivek Doshi

1
@ pro.mean, chúng tôi đã chuyển đổi chỉ để hiển thị điều đó ở phía mẫu, nhưng bạn vẫn có đối tượng Bản đồ mà bạn có thể sử dụng trong phía thành phần của mình. bạn có thể yêu cầu OP why he needed this kind of requirement, ông có thể giải thích cho bạn tốt hơn :)
Vivek Doshi

47

Nếu bạn đang sử dụng Angular 6.1 trở lên, cách thuận tiện nhất là sử dụng 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']]);
    }

3
Người hy vọng di chuyển và xem câu trả lời này, bởi vì tôi sắp sửa làm một cấu trúc lại cho đến khi tôi đã nhìn thấy điều này ống out-of-the-box có sẵn cho tôi maploại mà sẽ chăm sóc của việc sử dụng nó với*ngFor
atconway

2
có vẻ như, keyvalue không giữ được phân loại ban đầu của bản đồ :-(, bạn cần thêm hàm so sánh để khắc phục điều đó
Konstantin Vahrushev

1
Đây là sự thật. Và đây là sự cố github.com/angular/angular/issues/31420
Londeren

24

Biên tập

Đối với phiên bản 6.1 góc cạnh và mới hơn, hãy sử dụng KeyValuePipe theo đề xuất của Londeren.

Đối với góc 6.0 trở lên

Để làm cho mọi thứ dễ dàng hơn, bạn có thể tạo một đường ống.

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">

Vì nó thuần túy, nó sẽ không được kích hoạt khi phát hiện thay đổi, nhưng chỉ khi tham chiếu đến mapbiến thay đổi

Bản demo của Stackblitz


Tôi nghĩ rằng đường ống của bạn sẽ được kiểm tra các thay đổi và thực hiện lặp lại đầy đủ trên mọi chu kỳ phát hiện thay đổi vì nó không phải là "nguyên chất". Không bỏ phiếu nhưng có lẽ đó là lý do tại sao?
Drenai

5
@Ryan Pipes là thuần túy theo mặc định. Nếu bạn thêm console.log vào đường dẫn, bạn sẽ thấy rằng nó không nhận được cuộc gọi nhiều lần. Nhưng phương pháp thành phần trong giải pháp được chấp nhận không ...
David

1
Tôi đã lạc hậu! Cảm ơn vì đã quan tâm
Drenai

10

Điều này là do map.keys()trả về một trình lặp. *ngForcó thể hoạt động với các trình vòng lặp, nhưng map.keys()sẽ được gọi trong mỗi chu kỳ phát hiện thay đổi, do đó tạo ra một tham chiếu mới đến mảng, dẫn đến lỗi bạn thấy. Nhân tiện, đây không phải lúc nào cũng là một lỗi như bạn thường nghĩ về nó; nó thậm chí có thể không phá vỡ bất kỳ chức năng nào của bạn, nhưng gợi ý rằng bạn có một mô hình dữ liệu dường như hoạt động theo một cách điên rồ - thay đổi nhanh hơn so với trình phát hiện thay đổi kiểm tra giá trị của nó.

Nếu bạn không muốn chuyển đổi bản đồ thành một mảng trong thành phần của mình, bạn có thể sử dụng đường dẫn được đề xuất trong các nhận xét. Có vẻ như không có cách giải quyết nào khác.

PS Lỗi này sẽ không được hiển thị trong chế độ sản xuất, vì nó giống như một cảnh báo rất nghiêm ngặt hơn là một lỗi thực sự, nhưng vẫn không phải là một ý kiến ​​hay nếu để nó xảy ra.


1

Như mọi người đã đề cập trong phần nhận xét keyvalue pipe không giữ lại thứ tự chèn (đó là mục đích chính của Bản đồ).

Nhưng dù sao, có vẻ như nếu bạn có một đối tượng Bản đồ và muốn duy trì thứ tự, cách tốt nhất để làm như vậy là hàm entry ():

<ul>
    <li *ngFor="let item of map.entries()">
        <span>key: {{item[0]}}</span>
        <span>value: {{item[1]}}</span>
    </li>
</ul>

Vui lòng xem github.com/angular/angular/issues/31420#issuecomment-635377113 tại sao bạn nên tránh sử dụng .entries ()
Florian

1

Đoạn mã dưới đây hữu ích để hiển thị theo thứ tự chèn bản đồ .

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

tệp .ts thêm mã bên dưới.

asIsOrder(a, b) {
    return 1;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.