source

Angular에서 개체 위에 반복

manycodes 2023. 5. 6. 15:15
반응형

Angular에서 개체 위에 반복

2에서 몇 작업을 과 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 supporting object

내가 여기서 뭘 놓쳤지요?이것은 더 이상 불가능합니까?(첫 번째 구문은 Angular 1.x에서 작동) 또는 개체를 반복하기 위한 구문이 다릅니까?

Angular 6.1.0+ 정답

내장된 파이프를 다음과 같이 사용합니다.

<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에서도 작동합니다.

ng1의 구문을 지원하지 않으려는 것 같습니다.

미슈코 헤베리(참고 자료)에 따르면:

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

그 계획은 지도를 가지고 있는 것입니다.

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

이 파이프를 사용해 보세요.

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>

: 는 이제 "Angular": "Angular": "json Object"를 통해 위한 합니다.keyvalue:

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

작업 데모 및 자세한 내용은 읽기


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

구성 요소 측면:

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>

작업 데모

@obscur의 답변 외에도, 다음은 두 가지 모두에 액세스할 수 있는 방법의 예입니다.key그리고.value@보기.

파이프:

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

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

: 다리오
이름:이름:

파일:
이름:이름:그레이조이

파일:
: 공

사이먼 하우섬의 훌륭한 답변에 더해서요.저는 새로운 타자기 기능 중 일부를 활용한 간결한 버전을 만들었습니다.저는 사이먼 하우섬의 버전이 근본적인 세부 사항을 설명하기 위해 의도적으로 장황하다는 것을 알고 있습니다.파이프가 잘못된 값을 위해 작동하도록 조기 체크도 추가했습니다.예를 들어, 지도가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] }));
    }
}

다음은 다중 변환(키벌, 키, 값)을 지원하는 위 답변 중 일부에 대한 변형입니다.

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>

저도 비슷한 문제가 있었습니다. 객체와 지도를 위한 무언가를 만들었습니다.

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

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

다차원 객체를 사용하는 방법을 궁금해하는 사용자가 있다면 해결책은 다음과 같습니다.

다음과 같은 물체가 작동 중이라고 가정합니다.

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>

JSON 쿼리/api 호출에서 반환된 데이터를 분석하고 사용하려고 노력하면서 머리를 쥐어뜯고 있습니다.제가 어디서 잘못되고 있었는지 정확히 모르겠습니다. 며칠 동안 답을 빙빙 돌면서 다음과 같은 다양한 오류 코드를 쫓고 있는 것 같습니다.

"'iterableDiff' 파이프 지원 개체를 찾을 수 없습니다."

"일반 TYPE 어레이에는 하나의 인수가 필요합니다."

JSON 구문 분석 오류 및 기타 오류 확인

나는 내가 단지 잘못된 조합의 수정을 가졌을 뿐이라고 생각합니다.

그래서 여기에 gotchas와 찾아야 할 것들에 대한 요약이 있습니다.

먼저 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' 명령을 사용하여 파이프 모듈.ts가 올바르게 생성되고 참조되는지 확인합니다.다음을 내 페이지에 추가해야 합니다.module.ts 페이지

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

(사용자 고유의 custom_proxy가 있는 경우 이 값이 변경되면 custommodule.custom.ts에 이 값을 추가해야 할 수도 마찬가지입니다.

만약 당신이 당신의 페이지를 만들기 위해 'ionic generate page' 명령을 사용했지만, 그 페이지를 당신의 메인 페이지로 사용하기로 결정했다면, app.message.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);

이 정보 편집이 누군가에게 도움이 되길 바랍니다.

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

가장 간단한 해결책은 객체를 즉시 배열로 변환하는 파이프/필터를 만드는 것입니다.그렇긴 하지만, 당신은 @basarat이 말한 것처럼 배열을 사용하기를 원할 것입니다.

가지고 계신다면,es6-shim또는 당신의tsconfig.jsones6ES6 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>

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

TypeScript의 인터페이스는 개발 시간 구조입니다(단순히 툴링용... 런타임 영향 0).당신은 당신의 자바스크립트와 같은 타입스크립트를 작성해야 합니다.

「 」를 합니다.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">

파이프를 사용할 구성 요소에서 파이프 모듈을 선언해야 합니다.

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

그래서 Object(obj)만 반환하는 나만의 도우미 함수 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>

구조 지시어를 사용하여 객체를 루프하는 또 다른 방법이 있습니다.

저는 이 접근 방식이 일반적인 ngFor 루프와 가장 "느껴지기" 때문에 선호합니다. :-)

(예를 들어 이 경우 루프 내에서 액세스할 수 있는 Angular의 컨텍스트 변수를 i = 인덱스 | 짝수 | 홀수 | 번째 | 마지막 | 카운트) 추가했습니다.

@Directive({
  selector: '[ngForObj]'
})
export class NgForObjDirective implements OnChanges {

  @Input() ngForObjOf: { [key: string]: any };

  constructor(private templateRef: TemplateRef<any>, private viewContainerRef: ViewContainerRef) { }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.ngForObjOf && changes.ngForObjOf.currentValue) {
      // remove all views
      this.viewContainerRef.clear();

      // create a new view for each property
      const propertyNames = Object.keys(changes.ngForObjOf.currentValue);
      const count = propertyNames.length;

      propertyNames.forEach((key: string, index: number) => {
        const even = ((index % 2) === 0);
        const odd = !even;
        const first = (index === 0);
        const last = index === (count - 1);

        this.viewContainerRef.createEmbeddedView(this.templateRef, {
          $implicit: changes.ngForObjOf.currentValue[key],
          index,
          even,
          odd,
          count,
          first,
          last
        });
      });
    }
  }
}

템플릿의 사용량:

<ng-container *ngForObj="let item of myObject; let i = index"> ... </ng-container>

또한 정수 값을 사용하여 루프를 수행하려면 다음 지시문을 사용할 수 있습니다.

@Directive({
   selector: '[ngForInt]'
})
export class NgForToDirective implements OnChanges {

  @Input() ngForIntTo: number;
 
  constructor(private templateRef: TemplateRef<any>, private viewContainerRef: ViewContainerRef) {

  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.ngForIntTo && changes.ngForIntTo.currentValue) {
      // remove all views
      this.viewContainerRef.clear();

      let currentValue = parseInt(changes.ngForIntTo.currentValue);
      for (let index = 0; index < currentValue; index++) {
        this.viewContainerRef.createEmbeddedView(this.templateRef, {
          $implicit: index,
          index
        });
      }

    }

  }
}

템플릿의 사용량(예: 0 ~ 14(= 15회 반복):

<ng-container *ngForInt="let x to 15"> ... </ng-container>

언급URL : https://stackoverflow.com/questions/31490713/iterate-over-object-in-angular

반응형