Как выполнить итерацию с помощью цикла ngFor Карта, содержащая ключ как строку и значения как итерация карты

Я новичок в angular 5 и пытаюсь перебрать карту, содержащую другую карту в typescript. Как итерации ниже этого вида карты в angular ниже приведен код для компонента:

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

  }



}

и его шаблон html:

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


</ul>

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

ошибка времени выполнения

Ответ 1

Для Angular 6. 1+ вы можете использовать pipeу по умолчанию keyvalue (Делать обзор и повышать также):

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

РАБОЧАЯ ДЕМО


Для предыдущей версии:

Одним из простых решений этой проблемы является преобразование карты в массив: Array.from

Сторона компонента:

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

Сторона шаблона:

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

РАБОЧАЯ ДЕМО

Ответ 2

Если вы используете Angular 6.1 или новее, наиболее удобным способом является использование 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

Изменить

Для angular 6.1 и новее используйте KeyValuePipe, как предложено Londeren.

Для angular 6.0 и старше

Чтобы сделать вещи проще, вы можете создать pipeу.

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

Как он чист, он не будет срабатывать при каждом обнаружении изменений, но только в случае изменения ссылки на переменную map

Stackblitz демо

Ответ 4

Это потому, что map.keys() возвращает итератор. *ngFor может работать с итераторами, но map.keys() будет вызываться в каждом цикле обнаружения изменений, тем самым создавая новую ссылку на массив, в результате чего вы увидите ошибку. Кстати, это не всегда ошибка, о которой вы бы обычно думали; он может даже не нарушить вашу функциональность, но предполагает, что у вас есть модель данных, которая, по-видимому, ведет себя безумным образом - меняется быстрее, чем детектор изменений проверяет его значение.

Если вы не хотите преобразовывать карту в массив в своем компоненте, вы можете использовать канал, предложенный в комментариях. Нет другого способа обхода, как кажется.

P.S. Эта ошибка не будет отображаться в режиме производства, так как она скорее напоминает очень строгую предупреждение, а не фактическую ошибку, но, тем не менее, это не является хорошей идеей оставить ее.