Câu hỏi Lặp lại đối tượng trong Angular


Tôi đang cố gắng làm một số điều trong Angular 2 Alpha 28, và đang gặp vấn đề với từ điển và NgFor.

Tôi có một giao diện trong TypeScript trông như thế này:

interface Dictionary {
    [ index: string ]: string
}

Trong JavaScript, điều này sẽ chuyển thành một đối tượng có dữ liệu có thể trông giống như sau:

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

Tôi muốn lặp lại điều này và đã thử điều này:

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

Nhưng không có kết quả, không có cách nào dưới đây hoạt động:

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

Trong mọi trường hợp, tôi nhận được các lỗi như đối tượng hỗ trợ ống "Unexpected token" hoặc "Can't find 'iterableDiff'"

Tôi đang thiếu gì ở đây? Điều này là không thể nữa? (Cú pháp đầu tiên hoạt động trong Angular 1.x) hoặc là cú pháp khác nhau để lặp qua một đối tượng?


76
2017-07-18 11:30


gốc


"Từ điển" là gì? Tôi chưa bao giờ thấy hoặc nghe thuật ngữ đó trong ngữ cảnh JavaScript, Angular hoặc TypeScript. Y


Các câu trả lời:


Dường như họ không muốn hỗ trợ cú pháp từ ng1.

Theo Miško Hevery (tài liệu tham khảo):

Bản đồ không có đơn đặt hàng trong khóa và do đó họ lặp lại là không thể đoán trước.   Điều này đã được hỗ trợ trong ng1, nhưng chúng tôi nghĩ rằng đó là một sai lầm và sẽ không   được hỗ trợ trong NG2

Kế hoạch là có một ống mapToIterable

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

Vì vậy, để lặp qua đối tượng của bạn, bạn sẽ cần phải sử dụng một "đường ống". Hiện tại không có ống thực hiện điều đó.

Như một giải pháp thay thế, đây là một ví dụ nhỏ lặp lại các khóa:

Thành phần:

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
}

68
2017-07-21 11:22



tôi đang cố gắng trên đối tượng với key như number và value như string nhưng góc là ném lỗi expression has changed after it was checked ? tại sao nên có ý tưởng nào? - Pardeep Jain
Vâng, điều này cũng đang xảy ra với tôi. Và cũng vậy nếu tôi sử dụng giải pháp của @ obsur. - user2294382


cố gắng sử dụng ống này

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

60
2017-12-03 19:26



Rực rỡ, và nếu tôi muốn giữ tham chiếu đến khóa, tôi sẽ chỉ ánh xạ một đối tượng với cả khóa và giá trị thay thế. Tôi ước tôi có thể đánh dấu một số câu trả lời như câu trả lời được chấp nhận, vì đây là giải pháp cho vấn đề của tôi trong khi câu trả lời được đánh dấu là câu trả lời cho câu hỏi của tôi. - Rickard Staaf
@obscur - Nếu tôi làm ở trên bây giờ, tôi nhận được một lỗi "biểu hiện đã thay đổi sau khi nó đã được kiểm tra" bằng cách sử dụng angular2.beta.0.0. Có suy nghĩ gì không? - user2294382
Thats bởi vì pure: false đòi hỏi một detectionStrategy thay đổi để được tiêm - Judson Terrell
Tại sao thiết lập nó để không tinh khiết? - tom10271


Bản cập nhật năm 2018:

Như các câu trả lời khác đã đề cập, nó không được hỗ trợ trong ngx, do đó, đây là một giải pháp với cặp khóa-giá trị:

Ống:

import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
  name: 'mapToIterable'
})
export class MapToIterable implements PipeTransform {
  transform(dict: Object) {
    var a = [];
    for (var key in dict) {
      if (dict.hasOwnProperty(key)) {
        a.push({key: key, val: dict[key]});
      }
    }
    return a;
  }
}

Việc sử dụng:

<div *ngFor="let keyValuePair of someObject | mapToIterable">
  This is the key {{keyValuePair.key}} and this is the value {{keyValuePair.val}}.
</div>

Ví dụ về Stackblitz: https://stackblitz.com/edit/map-to-iterable-pipe


33
2018-02-08 01:14



Bạn nên thêm implements PipeTransform trong định nghĩa lớp (xem angular.io/guide/pipes#custom-pipes) - toioski
@toioski cảm ơn, tôi đã thêm nó và cập nhật cú pháp mới của vòng lặp for. - bersling
Câu trả lời tuyệt vời, sử dụng này để ngFor Từ điển của tôi. Tôi đã phải làm keyValuePair.val [0] mặc dù các giá trị của tôi đã kết thúc [{}] chứ không phải {} - jhhoff02
cảm ơn. Hoạt động tuyệt vời - Johansrk


Ngoài câu trả lời của @ obscur, đây là ví dụ về cách bạn có thể truy cập cả hai key và value từ @View.

Ống:

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

}

Lượt xem:

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

Vì vậy, nếu đối tượng trông giống như:

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

Kết quả được tạo ra sẽ là:

Tên: Daario
Họ: Naharis

Tên: Victarion
Họ: Greyjoy

Tên: Quentyn
Họ: Ball


18
2018-03-03 18:14



Làm việc cho tôi khá dễ dàng! Cảm ơn - Vlad
chỉ một điều cần đề cập bạn cần thay đổi Chế độ xem: dưới dạng <li *ngFor="let u of myObject | keyValueFilter">First Name: {{u.key}} <br> Last Name: {{u.value}}</li>. +1 từ tôi. - sib10
Tuyệt vời ! Cảm ơn bạn. - Maxime Lafarie


Thêm vào SimonHawesome's câu trả lời xuất sắc. Tôi đã tạo một phiên bản ngắn gọn, sử dụng một số tính năng mới của bản ghi. Tôi nhận ra rằng phiên bản của SimonHawesome cố ý tiết lộ chi tiết cơ bản. Tôi cũng đã thêm một kiểm tra sớm để ống hoạt động bịnh giá trị. Ví dụ: nếu bản đồ là null.

Lưu ý rằng việc sử dụng phép biến đổi vòng lặp (như được thực hiện ở đây) có thể hiệu quả hơn vì chúng ta không cần cấp phát bộ nhớ cho một mảng tạm thời (như đã hoàn thành trong một số câu trả lời khác).

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

12
2018-05-27 09:15



yêu chủ đề này, với một bình luận xây dựng ontop của người khác! Tôi sắp viết cùng một thứ khi tôi thấy mã của bạn - David
điều duy nhất trong giải pháp này: nó nên thực hiện PipeTransform - iRaS
@iRaS Điểm tốt. Tôi đã cập nhật câu trả lời của mình. Tôi cũng trả về undefined thay vì null. - Frederik Aalund


Dưới đây là một biến thể trên một số câu trả lời ở trên hỗ trợ nhiều biến đổi (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;
  }
}

Sử dụng

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>

9
2018-01-11 22:32



pure: false thực sự quan trọng đối với phản xạ tức thì. - Fırat KÜÇÜK


Tôi đã có một vấn đề tương tự, xây dựng một cái gì đó cho các đối tượng và 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;
  }
}


4
2018-04-13 23:27



Điều này hoạt động tốt, ngoại trừ trong TypeScript bạn nên thêm implements PipeTransform với định nghĩa lớp - GeorgDangl