Iterate over object in Angular

2019-01-01 02:02发布

I am trying to do some things in Angular 2 Alpha 28, and am having an issue with dictionaries and NgFor.

I have an interface in TypeScript looking like this:

interface Dictionary {
    [ index: string ]: string
}

In JavaScript this will translate to an object that with data might look like this:

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

I want to iterate over this and tried this:

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

But to no avail, none of the below worked either:

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

In all cases I get errors like "Unexpected token" or "Cannot find 'iterableDiff' pipe supporting object"

What am I missing here? Is this not possible anymore? (The first syntax works in Angular 1.x) or is the syntax different for iterating over an object?

标签: angular
15条回答
余欢
2楼-- · 2019-01-01 02:32

In addition to @obscur's answer, here is an example of how you can access both the key and value from the @View.

Pipe:

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

}

View:

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

So if the object were to look like:

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

The generated outcome would be:

First name: Daario
Last Name: Naharis

First name: Victarion
Last Name: Greyjoy

First name: Quentyn
Last Name: Ball

查看更多
不流泪的眼
3楼-- · 2019-01-01 02:32

Adding to SimonHawesome's excellent answer. I've made an succinct version which utilizes some of the new typescript features. I realize that SimonHawesome's version is intentionally verbose as to explain the underlying details. I've also added an early-out check so that the pipe works for falsy values. E.g., if the map is null.

Note that using a iterator transform (as done here) can be more efficient since we do not need to allocate memory for a temporary array (as done in some of the other answers).

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] }));
    }
}
查看更多
其实,你不懂
4楼-- · 2019-01-01 02:33

I had a similar issue, built something for objects and 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;
  }
}

查看更多
浪荡孟婆
5楼-- · 2019-01-01 02:33

In JavaScript this will translate to an object that with data might look like this

Interfaces in TypeScript are a dev time construct (purely for tooling ... 0 runtime impact). You should write the same TypeScript as your JavaScript.

查看更多
步步皆殇っ
6楼-- · 2019-01-01 02:38

Here's a variation on some of the above answers that supports multiple transforms (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;
  }
}

Usage

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>
查看更多
十年一品温如言
7楼-- · 2019-01-01 02:39

Updated : Angular is now providing the pipe for lopping through the json Object via keyvalue :

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

WORKING DEMO , and for more detail Read


Previously (For Older Version) : Till now the best / shortest answer I found is ( Without any Pipe Filter or Custom function from Component Side )

Component side :

objectKeys = Object.keys;

Template side :

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

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

</div>

WORKING DEMO

查看更多
登录 后发表回答