Angular에서 개체 반복


130

Angular 2 Alpha 28에서 몇 가지 작업을 시도하고 있으며 사전 및 NgFor에 문제가 있습니다.

TypeScript에 다음과 같은 인터페이스가 있습니다.

interface Dictionary {
    [ index: string ]: string
}

JavaScript에서 이것은 데이터가있는 객체로 변환됩니다.

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

나는 이것을 반복하고 이것을 시도하고 싶다.

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

그러나 소용이 없었지만 아래 중 어느 것도 작동하지 않았습니다.

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

모든 경우에 "Unexpected token"또는 "Cannot find 'iterableDiff'pipe support object"와 같은 오류가 발생합니다.

내가 여기서 무엇을 놓치고 있습니까? 더 이상 가능하지 않습니까? (첫 번째 구문은 Angular 1.x에서 작동합니다) 아니면 객체를 반복하는 구문이 다른가요?


"사전"이란 무엇입니까? JavaScript, Angular 또는 TypeScript 컨텍스트에서 해당 용어를 보거나들은 적이 없습니다. Y

사전은 내가 생각하는 맵을 의미합니다.이 용어는 JS 컨텍스트에서는 전혀 사용되지 않지만 Python 또는 Ruby에서는 사용됩니다.
Cesar Jr Rodriguez

2
나는 @bersling 대답이 이제이 질문에 대한 정답이라고 생각합니다.
Joshua Kissoon 2018

1
정답을 더 잘 표시하십시오. bersling이 정확합니다
activedecay

답변:


87

ng1의 구문을 지원하지 않는 것으로 보입니다.

Miško Hevery에 따르면 ( 참조 ) :

맵에는 키에 순서가 없으므로 반복을 예측할 수 없습니다. 이것은 ng1에서 지원되었지만 실수라고 생각하고 NG2에서 지원되지 않을 것입니다

계획은 mapToIterable 파이프를 갖는 것입니다.

<div *ngFor"var item of map | mapToIterable">

따라서 개체를 반복하려면 "파이프"를 사용해야합니다. 현재이를 수행하는 파이프 가 없습니다 .

해결 방법으로 다음은 키를 반복하는 작은 예입니다.

구성 요소:

import {Component} from 'angular2/core';

@Component({
  selector: 'component',
  templateUrl: `
       <ul>
       <li *ngFor="#key of keys();">{{key}}:{{myDict[key]}}</li>
       </ul>
  `
})
export class Home {
  myDict : Dictionary;
  constructor() {
    this.myDict = {'key1':'value1','key2':'value2'};
  }

  keys() : Array<string> {
    return Object.keys(this.myDict);
  }
}

interface Dictionary {
    [ index: string ]: string
}

1
keyas numbervalueas로 객체에 대해 동일하게 시도하고 string있지만 각도가 오류를 던지고 expression has changed after it was checked있습니까? 왜 그렇게 생각합니까?
Pardeep Jain

그래 나도 이런 일이 일어나고있다. @obsur의 솔루션을 사용하는 경우에도 마찬가지입니다.
user2294382

1
최신 각도 7에 대한 사소한 해결책이 있기 때문에 bersling의 답변을 참조하십시오.
activedecay

156

Angular 6.1.0+ 답변

다음과 같이 내장 keyvalue-pipe를 사용하십시오 .

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

또는 다음과 같이 :

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

파일의 위치 mySortingFunction는 다음과 .ts같습니다.

mySortingFunction = (a, b) => {
  return a.key > b.key ? -1 : 1;
}

Stackblitz : https://stackblitz.com/edit/angular-iterate-key-value

Angular 파이프는 모든 템플릿에서 즉시 작동하므로 어떤 모듈에도 등록 할 필요가 없습니다.

Javascript-Maps 에서도 작동합니다 .


당신은 추가해야 implements PipeTransform클래스 정의에 (참조 angular.io/guide/pipes#custom-pipes를 )
toioski

1
@toioski 감사합니다, 나는 그것을 추가하고 for 루프의 새로운 구문으로 업데이트했습니다.
bersling

좋은 대답, 이것을 ngFor my Dictionary에 사용했습니다. 나는 keyValuePair.val을해야했다 [0] 내 값은 [{}]이 아닌 {} 결국 같은 생각
jhhoff02을

1
이것보다 장점이 return Object.keys(dict).map(key => ({key, val: dict[key]}))있습니까?
Justin Morgan

나는 아무것도 보이지 않는다, 실제로 나는 당신의 방식을 사용할 것이다!
bersling

72

이 파이프를 사용해보십시오

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

@Pipe({ name: 'values',  pure: false })
export class ValuesPipe implements PipeTransform {
  transform(value: any, args: any[] = null): any {
    return Object.keys(value).map(key => value[key]);
  }
}

<div *ngFor="#value of object | values"> </div>

5
훌륭합니다. 키에 대한 참조를 유지하려면 대신 키와 값을 모두 사용하여 개체를 매핑합니다. 표시된 답변이 내 질문에 대한 답변 인 동안 이것이 내 문제에 대한 해결책이기 때문에 여러 답변을 수락 된 답변으로 표시 할 수 있기를 바랍니다.
리 카드 Staaf

1
@obscur-지금 위의 작업을 수행하면 angular2.beta.0.0을 사용하여 "표현식이 확인 된 후 변경되었습니다"라는 오류가 발생합니다. 이견있는 사람?
user2294382

그 이유는 pure : false를 사용하려면 변경 감지
전략을

1
왜 그것을 불결하게 설정합니까?
tom10271

이것은 나를 위해 잘 작동했습니다. 유일한 것은 ngFor에서 #을 사용할 수 없다는 것입니다. 대신 let을 사용했습니다.
MartinJH

19

@obscur의 답변 외에도 다음 key과 같이 액세스 할 수있는 방법의 예가 있습니다.value @View 대한 예가 있습니다.

파이프:

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

}

전망:

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

따라서 개체가 다음과 같은 경우 :

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

생성 된 결과는 다음과 같습니다.

이름 : Daario
성 : Naharis

이름 : Victarion
성 : Greyjoy

이름 : Quentyn
성 : Ball


2
뷰를 변경하려면 한 가지 언급해야합니다 <li *ngFor="let u of myObject | keyValueFilter">First Name: {{u.key}} <br> Last Name: {{u.value}}</li>. 나에게서 +1.
sib10

지도 기능 내부의 코드는 다음과 같이 단순화 할 수 있습니다. return { 'key' : key, 'value' : value[key] };
Makotosan

17

업데이트 : Angular는 이제 다음을 통해 json 객체를 통해 lopping하는 파이프를 제공합니다 keyvalue.

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

WORKING DEMO , 자세한 내용은 읽기


이전 (이전 버전의 경우) : 지금까지 내가 찾은 가장 좋은 / 가장 짧은 대답은 (구성 요소 측의 파이프 필터 또는 사용자 정의 기능 없음)입니다.

구성 요소 측면 :

objectKeys = Object.keys;

템플릿 측면 :

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

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

</div>

작업 데모


1
let item of myDict | keyvalue이것은 내 문제를 해결했습니다.
Silambarasan RD

13

SimonHawesome의 탁월한 답변에 추가합니다 . 새로운 typescript 기능을 활용하는 간결한 버전을 만들었습니다. 나는 SimonHawesome의 버전이 근본적인 세부 사항을 설명하기 위해 의도적으로 장황하다는 것을 알고 있습니다. 파이프가 허위 값에 대해 작동하도록 조기 체크를 추가했습니다 . 예 :지도가null .

반복기 변환 (여기에서 수행됨)을 사용하면 임시 배열에 메모리를 할당 할 필요가 없기 때문에 더 효율적일 수 있습니다 (다른 답변 중 일부에서 수행됨).

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

3
이 스레드를 사랑합니다. 내가 코드보고에 대해 같은 일을 작성했다
데이비드

3
이 솔루션의 유일한 것 : 구현해야합니다PipeTransform
iRaS

@iRaS 좋은 지적입니다. 내 답변을 업데이트했습니다. 또한 null 대신 undefined를 반환합니다.
Frederik Aalund 2017-06-29

9

다음은 여러 변환 (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;
  }
}

용법

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>

1
pure: false즉석 반사에 정말 중요합니다.
Fırat KÜÇÜK

4

비슷한 문제가 발생하여 사물과지도를위한 무언가를 만들었습니다.

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


1
즉, 타이프 라이터에 추가해야한다를 제외하고이 잘 작동 implements PipeTransform클래스 정의에
GeorgDangl

3

Angular 2.x && Angular 4.x는 기본적으로 이것을 지원하지 않습니다.

이 두 파이프를 사용하여 또는 으로 반복 할 수 있습니다 .

키 파이프 :

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

@Pipe({
  name: 'keys',
  pure: false
})
export class KeysPipe implements PipeTransform {
  transform(value: any, args: any[] = null): any {
    return Object.keys(value)
  }
}

값 파이프 :

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

@Pipe({
  name: 'values',
  pure: false
})
export class ValuesPipe implements PipeTransform {
  transform(value: any, args: any[] = null): any {
    return Object.keys(value).map(key => value[key])
  }
}

사용하는 방법:

let data = {key1: 'value1', key2: 'value2'}

<div *ngFor="let key of data | keys"></div>
<div *ngFor="let value of data | values"></div>

2

누군가가 다차원 객체로 작업하는 방법을 궁금해한다면 여기에 해결책이 있습니다.

서비스에 다음 객체가 있다고 가정하겠습니다.

getChallenges() {
    var objects = {};
    objects['0'] = { 
        title: 'Angular2', 
        description : "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."
    };

    objects['1'] = { 
        title: 'AngularJS', 
        description : "Lorem Ipsum is simply dummy text of the printing and typesetting industry."
    };

    objects['2'] = { 
        title: 'Bootstrap',
        description : "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
    };
    return objects;
}

구성 요소에서 다음 기능 추가

challenges;

constructor(testService : TestService){
    this.challenges = testService.getChallenges();
}
keys() : Array<string> {
    return Object.keys(this.challenges);
}

마지막으로 다음을 수행하십시오.

<div *ngFor="#key of keys();">
    <h4 class="heading">{{challenges[key].title}}</h4>
    <p class="description">{{challenges[key].description}}</p>
</div>

2

JSON 쿼리 / API 호출에서 반환 된 데이터를 구문 분석하고 사용하려고 시도하면서 머리카락을 찢어 냈습니다. 내가 어디로 잘못 가고 있는지 정확히 모르겠습니다. 나는 며칠 동안 대답을 돌면서 다음과 같은 다양한 오류 코드를 쫓는 것처럼 느낍니다.

" 'iterableDiff'파이프 지원 개체를 찾을 수 없음"

"일반 유형 배열에는 하나의 인수가 필요합니다."

JSON 구문 분석 오류 및 다른 사람이 확실하지 않음

나는 내가 잘못된 수정 조합을 가지고 있다고 가정합니다.

그래서 여기에 몇 가지 문제점과 찾아봐야 할 것들에 대한 요약이 있습니다.

먼저 API 호출의 결과를 확인하십시오. 결과는 객체, 배열 또는 객체 배열 형식 일 수 있습니다.

나는 그것에 너무 많이 들어 가지 않을 것입니다. OP의 원래 오류가 반복 가능하지 않다는 것은 일반적으로 배열이 아닌 객체를 반복하려고 할 때 발생합니다.

배열과 객체의 변수를 보여주는 디버깅 결과 중 일부는 다음과 같습니다.

따라서 일반적으로 JSON 결과를 반복하고자하므로 배열 형식인지 확인해야합니다. 나는 수많은 예제를 시도해 보았고 아마도 지금 내가 아는 것이 실제로 작동하는 것을 알고 있었지만 실제로 사용한 접근 방식은 파이프를 구현하는 것이었고 내가 사용한 코드는 t.888에 의해 게시되었습니다.

   transform(obj: {[key: string]: any}, arg: string) {
if (!obj)
        return undefined;

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;

솔직히 저는 '정의되지 않은 반환'호출을 추가하여 오류 처리가 부족하다고 생각합니다. 이제 예상치 못한 데이터를 파이프로 보낼 수 있다고 생각합니다. .

파이프에 대한 논쟁을 다루고 싶지 않다면 (대부분의 경우 필요하지 않다고 생각합니다) 다음을 반환 할 수 있습니다

       if (!obj)
          return undefined;
       return Object.keys(obj);

파이프 및 해당 파이프를 사용하는 페이지 또는 구성 요소를 만드는 데 대한 몇 가지 참고 사항

'name_of_my_pipe'에 대한 오류가 발견되지 않았습니까?

CLI에서 'ionic generate pipe'명령을 사용하여 파이프 modules.ts가 올바르게 작성되고 참조되는지 확인하십시오. mypage.module.ts 페이지에 다음을 추가했는지 확인하십시오.

import { PipesModule } from ‘…/…/pipes/pipes.module’;

(자신의 custom_module도 가지고 있다면 이것이 변경되는지 확실하지 않으면 custommodule.module.ts에 추가해야 할 수도 있습니다)

'ionic generate page'명령을 사용하여 페이지를 만들었지 만 해당 페이지를 기본 페이지로 사용하기로 결정한 경우 app.module.ts에서 페이지 참조를 제거해야합니다 (여기에 게시 한 또 다른 답변이 있습니다. https : /에 . /forum.ionicframework.com/t/solved-pipe-not-found-in-custom-component/95179/13?u=dreaser

html 파일에 데이터를 표시하는 여러 가지 방법이있는 답변을 검색 할 때 차이점을 설명 할만큼 충분히 이해하지 못합니다. 특정 시나리오에서는 서로 사용하는 것이 더 나을 수 있습니다.

            <ion-item *ngFor="let myPost of posts">
                  <img src="https://somwhereOnTheInternet/{{myPost.ImageUrl}}"/>
                  <img src="https://somwhereOnTheInternet/{{posts[myPost].ImageUrl}}"/>
                  <img [src]="'https://somwhereOnTheInternet/' + myPost.ImageUrl" />
            </ion-item>

그러나 값과 키를 모두 표시 할 수 있었던 것은 다음과 같습니다.

    <ion-list>  
      <ion-item *ngFor="let myPost of posts  | name_of_pip:'optional_Str_Varible'">

        <h2>Key Value = {{posts[myPost]}} 

        <h2>Key Name = {{myPost}} </h2>

      </ion-item>
   </ion-list>  

API 호출을하려면 HttpModule을 app.module.ts로 가져와야하는 것 같습니다.

import { HttpModule } from '@angular/http';
 .
 .  
 imports: [
BrowserModule,
HttpModule,

호출하는 페이지에 Http가 필요합니다.

import {Http} from '@angular/http';

API 호출을 할 때 하위 데이터 (배열 내의 객체 또는 배열)를 얻을 수있는 것처럼 보입니다. 두 가지 방법 중 하나가 작동하는 것 같습니다.

통화 중에

this.http.get('https://SomeWebsiteWithAPI').map(res => res.json().anyChildren.OrSubChildren).subscribe(
        myData => {

또는 지역 변수에 데이터를 할당 할 때

posts: Array<String>;    
this.posts = myData['anyChildren'];

(그 변수가 배열 문자열이어야하는지 확실하지 않지만 지금은 그게 내가 가지고있는 것입니다.보다 일반적인 변수로 작동 할 수 있습니다)

마지막으로, 내장 된 JSON 라이브러리를 사용할 필요는 없지만 객체에서 문자열로 변환하는 데이 두 가지 호출이 편리하다는 것을 알 수 있습니다.

        var stringifiedData = JSON.stringify(this.movies);                  
        console.log("**mResults in Stringify");
        console.log(stringifiedData);

        var mResults = JSON.parse(<string>stringifiedData);
        console.log("**mResults in a JSON");
        console.log(mResults);

이 정보 모음이 누군가에게 도움이되기를 바랍니다.


2
//Get solution for ng-repeat    
//Add variable and assign with Object.key

    export class TestComponent implements OnInit{
      objectKeys = Object.keys;
      obj: object = {
        "test": "value"
        "test1": "value1"
        }
    }
    //HTML
      <div *ngFor="let key of objectKeys(obj)">
        <div>
          <div class="content">{{key}}</div>
          <div class="content">{{obj[key]}}</div>
        </div>

1

JavaScript에서 이것은 데이터가있는 객체로 변환됩니다.

TypeScript의 인터페이스는 개발 시간 구조입니다 (순전히 도구 용 ... 런타임 영향 0). JavaScript와 동일한 TypeScript를 작성해야합니다.


그건 사실이 아니야. type 스크립트는 더 깨끗한 코드를 작성하도록합니다. 클래스를 추상화하기가 훨씬 쉽습니다. 당신은 단순히 가지고 있지 않습니다. C ++는 일부 asm으로 컴파일됩니다. asm에는 클래스 나 유형도 없습니다. 그럼에도 불구하고 다른 C ++를 작성하고 asm 코드를 작성합니다. : P
YAMM

1

사전은 배열이 아니라 객체입니다. ng-repeat에는 Angular 2의 배열이 필요하다고 생각합니다.

가장 간단한 해결책은 객체를 즉시 배열로 변환하는 파이프 / 필터를 만드는 것입니다. 즉, @basarat가 말한 것처럼 배열을 사용하고 싶을 것입니다.


1

당신이 es6-shim또는 당신의 tsconfig.json목표 를 가지고 있다면 es6, 당신은 그것을 만들기 위해 ES6 Map 을 사용할 수 있습니다 .

var myDict = new Map();
myDict.set('key1','value1');
myDict.set('key2','value2');

<div *ngFor="let keyVal of myDict.entries()">
    key:{{keyVal[0]}}, val:{{keyVal[1]}}
</div>

0

PipeTransform 정의 MapValuesPipe및 구현 :

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

@Pipe({name: 'mapValuesPipe'})
export class MapValuesPipe implements PipeTransform {
    transform(value: any, args?: any[]): Object[] {
        let mArray: 
        value.forEach((key, val) => {
            mArray.push({
                mKey: key,
                mValue: val
            });
        });

        return mArray;
    }
}

파이프 모듈에 파이프를 추가하십시오. 둘 이상의 구성 요소에서 동일한 파이프 를 사용해야하는 경우 중요합니다 .

@NgModule({
  imports: [
    CommonModule
  ],
  exports: [
    ...
    MapValuesPipe
  ],
  declarations: [..., MapValuesPipe, ...]
})
export class PipesAggrModule {}

그런 다음 HTML에서 파이프를 다음과 함께 사용하십시오 *ngFor.

<tr *ngFor="let attribute of mMap | mapValuesPipe">

파이프를 사용하려는 구성 요소에서 PipesModule을 선언해야합니다.

@NgModule({
  imports: [
    CommonModule,
    PipesAggrModule
  ],
...
}
export class MyModule {}

0

그래서 Object (obj) .keys.length 만 반환하는 헬퍼 함수 인 objLength (obj)를 구현하려고했습니다. 하지만 템플릿 * ngIf 함수에 추가 할 때 IDE가 objectKeys ()를 제안했습니다. 나는 그것을 시도하고 작동했습니다. 선언에 이어 lib.es5.d.ts에서 제공하는 것으로 보입니다.

구현 방법은 다음과 같습니다 (업로드 한 파일의 색인으로 서버 측 생성 키를 사용하는 사용자 지정 개체가 있습니다).

        <div *ngIf="fileList !== undefined && objectKeys(fileList).length > 0">
          <h6>Attached Files</h6>
          <table cellpadding="0" cellspacing="0">
            <tr *ngFor="let file of fileList | keyvalue">
              <td><a href="#">{{file.value['fileName']}}</a></td>
              <td class="actions">
                <a title="Delete File" (click)="deleteAFile(file.key);">
                </a>
              </td>
            </tr>
          </table>
        </div>
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.