【问题标题】:access key and value of object using *ngFor使用 *ngFor 访问对象的键和值
【发布时间】:2016-06-02 18:38:19
【问题描述】:

在使用*ngFor 迭代对象时,我对如何在angular2 中获取对象的keyvalue 有点困惑。我知道在 Angular 1.x 中有类似

的语法
ng-repeat="(key, value) in demo"

但我不知道如何在 angular2 中做同样的事情。我尝试过类似的方法,但没有成功:

    <ul>
      <li *ngFor='#key of demo'>{{key}}</li>
    </ul>

    demo = {
        'key1': [{'key11':'value11'}, {'key12':'value12'}],
        'key2': [{'key21':'value21'}, {'key22':'value22'}],
      }

这是我尝试的 plnkr: http://plnkr.co/edit/mIj619FncOpfdwrR0KeG?p=preview

如何使用*ngFor 动态获取key1key2?经过广泛搜索,我发现了使用管道的想法,但我不知道如何去做。 在 angular2 中是否有任何内置管道可以做同样的事情?

【问题讨论】:

  • 目前在 angular2 ngFor 中不支持key, value pair 语法,你应该看看this answer
  • @PankajParkar 是的,已经阅读了这个答案。现在有替代品吗?
  • @Pradeep 我现在想不出任何其他方法,你应该为此创建自己的Pipe..
  • 嗯,但我不知道如何为它创建管道。
  • @Pradeep 我给你的答案供你参考,有这个实现。他们应该工作..

标签: angular typescript object


【解决方案1】:

Angular 的最新版本 (v6.1.0) 一样,Angular 团队添加了新的内置管道,名称与 keyvalue 管道相同,以帮助您遍历对象、映射和数组,在角度包的common 模块中。 比如——

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

要保持原始顺序,请使用keyvalue:onCompare,
并在组件中定义回调:

// ...
import {KeyValue} from '@angular/common';

@Component(/* ... */)
export class MyComponent {
  private onCompare(_left: KeyValue<any, any>, _right: KeyValue<any, any>): number {
    return -1;
  }
}

Working Forked Example

在这里查看更多有用的信息 -

如果您使用的是 Angular v5 或更低版本,或者您想使用管道实现,请遵循此答案

【讨论】:

  • 大声笑我必须更新 ng6 才能访问这个管道 - 很棒的东西 - thx
  • 您可以使用自定义比较器保持原始键顺序:*ngFor="let item of testObject | keyvalue:keepOriginalOrder" 并在您的类中定义:public keepOriginalOrder = (a, b) =&gt; a.key
  • public keepOriginalOrder = (a, b) => a.key 非常感谢
  • 这应该是答案 - 在 angular 7 上运行良好
  • 令人难以置信的是,自从第一个版本以来,它就没有了
【解决方案2】:

在模板中可访问Object.keys,并在*ngFor 中使用它。

@Component({
  selector: 'app-myview',
  template: `<div *ngFor="let key of objectKeys(items)">{{key + ' : ' + items[key]}}</div>`
})

export class MyComponent {
  objectKeys = Object.keys;
  items = { keyOne: 'value 1', keyTwo: 'value 2', keyThree: 'value 3' };
  constructor(){}
}

【讨论】:

  • 这是一个更好更高效的解决方案
  • @tomtastico 你将如何为 3D 数组显示这个?例如 {"1": {"1.1": ["1.1.1","1.1.2"]}}。然后嵌套3个ngFor的
  • @Frank 你自己说的。嵌套*ngFors。前两个使用objectKeys,最里面不需要(因为它只是一个数组)。
  • 太棒了。设置 objectKeys = Object.keys 是我见过的能够从 HTML 检查对象长度的最简单方法。
【解决方案3】:

您可以创建一个自定义管道来返回每个元素的键列表。 类似的东西:

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

@Pipe({name: 'keys'})
export class KeysPipe implements PipeTransform {
  transform(value, args:string[]) : any {
    let keys = [];
    for (let key in value) {
      keys.push(key);
    }
    return keys;
  }
}

并像这样使用它:

<tr *ngFor="let c of content">           
  <td *ngFor="let key of c | keys">{{key}}: {{c[key]}}</td>
</tr>

编辑

您还可以返回一个包含键和值的条目:

@Pipe({name: 'keys'})
export class KeysPipe implements PipeTransform {
  transform(value, args:string[]) : any {
    let keys = [];
    for (let key in value) {
      keys.push({key: key, value: value[key]});
    }
    return keys;
  }
}

并像这样使用它:

<span *ngFor="let entry of content | keys">           
  Key: {{entry.key}}, value: {{entry.value}}
</span>

【讨论】:

  • 注意keys.push({key: key, value: value[key]);中缺少的右括号
  • 我实际上不鼓励任何人使用管道在*ngFor 表达式中创建集合。它造成了巨大的性能瓶颈,因为它需要在每次更改检测器检查更改时生成集合。
  • 感谢您的解决方案...问题是每当对象更改时,管道都不会更新。如果我将pure:false 添加到管道中,它会变得非常低效。每当我更改对象(删除项目)时,您是否有手动更新管道的解决方案?
  • 答案有点过时了。行 *ngFor="#entry of content | keys" 不能正常工作,for ... in 循环最好改为“for (const key of Object.keys(value))”
  • @RachChen 不在模板中:common: NgFor has been removed as it was deprecated since v4. Use NgForOf instead. This does not impact the use of*ngFor in your templates. (jaxenter.com/road-to-angular-5-133253.html)
【解决方案4】:

更新

6.1.0-beta.1 中引入了 KeyValuePipe https://github.com/angular/angular/pull/24319

<div *ngFor="let item of {'b': 1, 'a': 1} | keyvalue">
  {{ item.key }} - {{ item.value }}
</div>

Plunker Example

以前的版本

另一种方法是创建NgForIn 指令,其用法如下:

<div *ngFor="let key in obj">
   <b>{{ key }}</b>: {{ obj[key] }}
</div>

Plunker Example

ngforin.directive.ts

@Directive({
  selector: '[ngFor][ngForIn]'
})
export class NgForIn<T> extends NgForOf<T> implements OnChanges {

  @Input() ngForIn: any;

  ngOnChanges(changes: NgForInChanges): void {
    if (changes.ngForIn) {
      this.ngForOf = Object.keys(this.ngForIn) as Array<any>;

      const change = changes.ngForIn;
      const currentValue = Object.keys(change.currentValue);
      const previousValue = change.previousValue ? Object.keys(change.previousValue) : undefined;
      changes.ngForOf =  new SimpleChange(previousValue, currentValue, change.firstChange);

      super.ngOnChanges(changes);
    }
  }
}

【讨论】:

    【解决方案5】:

    从 Angular 6.1 开始,您可以使用 keyvalue 管道:

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

    但是它有一个不方便的地方是按键值对结果列表进行排序。 如果你需要一些中性的东西:

    @Pipe({ name: 'keyValueUnsorted', pure: false  })
    export class KeyValuePipe implements PipeTransform {
      transform(input: any): any {
        let keys = [];
        for (let key in input) {
          if (input.hasOwnProperty(key)) {
            keys.push({ key: key, value: input[key]});
          }
        }
        return keys;
      }
    }
    

    不要忘记指定 pure:false 管道属性。在这种情况下,管道会在每个更改检测周期中调用,即使输入引用没有更改(向对象添加属性时也是如此)。

    【讨论】:

    • 已经在stackoverflow.com/a/51491848/5043867上面分享了相同的答案
    • @PardeepJain 请让其他人也分享 :) !答案的第二部分是我需要的
    • @minigeek 不同的解决方案总是受欢迎的伙伴。但是,当我发布评论时,您所指的第二部分丢失了,只有第一部分与已接受的答案重复。您可以查看答案历史记录的更改日志。
    • @PardeepJain。是的,你的回答和那个人的评论只帮助我解决了问题。我理解你对剽窃的感觉:p
    【解决方案6】:

    用例子详细说明@Thierry 的答案。

    没有内置管道或方法可以从 *ngFor 循环中获取 key and value。所以我们必须为此创建自定义管道。正如 thierry 所说,这里是代码的答案。

    ** 管道类实现了 PipeTransform 接口的 transform 方法,该方法接受一个输入值和一个可选的参数字符串数组并返回转换后的值。

    ** transform 方法对于管道是必不可少的。 PipeTransform 接口定义该方法并指导工具和编译器。它是可选的;不管怎样,Angular 都会寻找并执行 transform 方法。 有关管道的更多信息refer here

    import {Component, Pipe, PipeTransform} from 'angular2/core';
    import {CORE_DIRECTIVES, NgClass, FORM_DIRECTIVES, Control, ControlGroup, FormBuilder, Validators} from 'angular2/common';
    
    @Component({
        selector: 'my-app',
        templateUrl: 'mytemplate.html',
        directives: [CORE_DIRECTIVES, FORM_DIRECTIVES],
        pipes: [KeysPipe]
    })
    export class AppComponent { 
    
      demo = {
        'key1': 'ANGULAR 2',
        'key2': 'Pardeep',
        'key3': 'Jain',
      }
    }
    
    
    @Pipe({name: 'keys'})
    export class KeysPipe implements PipeTransform {
      transform(value, args:string[]) : any {
        let keys = [];
        for (let key in value) {
          keys.push({key: key, value: value[key]});
        }
        return keys;
      }
    }
    

    而 HTML 部分是:

    <ul>
      <li *ngFor='#key of demo | keys'>
       Key: {{key.key}}, value: {{key.value}}
      </li>
    </ul>
    

    工作 Plnkr http://plnkr.co/edit/50LlK0k6OnMnkc2kNHM2?p=preview

    更新到 RC

    正如用户6123723(谢谢)在评论中所建议的,这里是更新。

    <ul>
      <li *ngFor='let key of demo | keys'>
       Key: {{key.key}}, value: {{key.value}}
      </li>
    </ul>
    

    【讨论】:

    • 这需要更新:这是我在表达式中得到的警告“#”已弃用。改用“让”! (" -->
      • ]*ngFor='#key of demo| keys'> 键:{{key.key}},值:{ {key.value}}
      • "): myComponent@56:6
    • 不确定这是否是新的,但可以从文档中引用:> 我们必须将管道包含在 AppModule 的声明数组中。
    【解决方案7】:

    @Marton 对接受的答案提出了重要反对,理由是管道在每次更改检测时都会创建一个新集合。相反,我会创建一个 HtmlService,它提供了视图可以使用的一系列实用功能,如下所示:

    @Component({
      selector: 'app-myview',
      template: `<div *ngFor="let i of html.keys(items)">{{i + ' : ' + items[i]}}</div>`
    })
    export class MyComponent {
      items = {keyOne: 'value 1', keyTwo: 'value 2', keyThree: 'value 3'};
      constructor(private html: HtmlService){}
    }
    
    @Injectable()
    export class HtmlService {
      keys(object: {}) {
        return Object.keys(object);
      }
      // ... other useful methods not available inside html, like isObject(), isArray(), findInArray(), and others...
    }
    

    【讨论】:

    • 这比 *ngFor 中的 Object.keys(...) 更好吗?
    • 因为它会抛出:TypeError: Cannot read property 'keys' of undefined。模板中似乎不支持。
    • 这作为一种解决方案非常有效,并且避免了上面指出的性能问题。 stackoverflow.com/questions/35534959/…
    • 你好,这个 b 可以不在template选项中使用,而是在模板的实际html代码中使用吗?谢谢
    【解决方案8】:

    如果你已经在使用 Lodash,你可以使用这个简单的方法,包括键和值:

    <ul>
      <li *ngFor='let key of _.keys(demo)'>{{key}}: {{demo[key]}}</li>
    </ul>
    

    在打字稿文件中,包括:

    import * as _ from 'lodash';
    

    在导出的组件中,包括:

    _: any = _;
    

    【讨论】:

    • 对不起,但不需要使用像 Lodash 这样的额外库来处理这些事情。无论如何,总是欢迎新方法:)
    【解决方案9】:

    想为 Angular 8 添加答案:

    对于循环,你可以这样做:

    <ng-container *ngFor="let item of BATCH_FILE_HEADERS | keyvalue: keepOriginalOrder">
       <th nxHeaderCell>{{'upload.bulk.headings.'+item.key |translate}}</th>
    </ng-container>
    

    此外,如果您需要上述数组来保持原始顺序,请在您的类中声明:

    public keepOriginalOrder = (a, b) => a.key;
    

    【讨论】:

    • 如果你也添加工作示例会很棒,stackblitz 可能是
    • @PardeepJain,我想要更复杂的。
    【解决方案10】:

    感谢管道,但我必须先进行一些更改,然后才能在 Angular 2 RC5 中使用它。更改了 Pipe 导入行,并在键数组初始化中添加了 any 类型。

     import {Pipe, PipeTransform} from '@angular/core';
    
     @Pipe({name: 'keys'})
     export class KeysPipe implements PipeTransform {
     transform(value) {
       let keys:any = [];
       for (let key in value) {
          keys.push( {key: key, value: value[key]} );
        }
         return keys;
      }
    }
    

    【讨论】:

    • 是的,进口已经改变了
    【解决方案11】:

    使用索引:

    <div *ngFor="let value of Objects; index as key">
    

    用法:

    {{key}} -> {{value}}
    

    【讨论】:

    • 这对我来说是新事物,如果您可以在答案中添加示例,那就更好了:) 您还可以为我指出任何相同的文档吗?
    • 什么是对象的类型?数组还是地图?请说清楚。提前致谢
    • 在这个例子中,“key”是索引。这与问题无关,无法访问真正的密钥
    【解决方案12】:

    这里没有一个对我有用的答案,这对我有用:

    使用内容创建pipes/keys.ts

    import { Pipe, PipeTransform } from '@angular/core';
    
    @Pipe({name: 'keys'})
    export class KeysPipe implements PipeTransform
    {
        transform(value:any, args:string[]): any {
            let keys:any[] = [];
            for (let key in value) {
                keys.push({key: key, value: value[key]});
            }
            return keys;
        }
    }
    

    添加到app.module.ts(您的主模块):

    import { KeysPipe } from './pipes/keys';
    

    然后在你的模块声明数组中添加如下内容:

    @NgModule({
        declarations: [
            KeysPipe
        ]
    })
    export class AppModule {}
    

    然后在您的视图模板中,您可以使用如下内容:

    <option *ngFor="let entry of (myData | keys)" value="{{ entry.key }}">{{ entry.value }}</option>
    

    Here 是我找到的一个很好的参考资料,如果您想了解更多信息。

    【讨论】:

    • 我可以知道您的答案与上面提供的其他答案(仅使用管道)之间有什么区别吗?好像和上面一样
    • 当然 1. 上面的示例使用 *ngFor="#entry" 而不是 *ngFor="let entry of" 并且我的编译器不接受 #entry 语法,参考不使用# 任何一个。 “let entry of (myData | keys)”似乎是一个更好的解决方案。 2. 我的编译器也没有验证示例管道类,因为它缺少显式数据类型,所以我添加了它。 3.上面的例子没有展示如何将管道集成到我的回答中的项目中,您需要将它导入到主模块中。
    • 哈哈是的,是的,因为当时给出的答案包括#等语法。顺便说一句,你的答案无疑也是正确的
    【解决方案13】:

    您可以使用keyvalue管道作为提供的示例代码:

        <div style="flex-direction: column">
            <app-cart-item
                class="cart-item"
                *ngFor="let keyValuePair of this.allProductRecords | keyvalue"
                [productRecord]="keyValuePair.value"
                (removeProduct)="removeProductFromCart(keyValuePair.key)"
            ></app-cart-item>
            <br />
            <p style="font-family: Verdana, Geneva, Tahoma, sans-serif; font-weight: bolder">
                Total ${{ getTotalPurchaseAmount() }}
            </p>
        </div>
    

    【讨论】:

      【解决方案14】:

      在其他漂亮的管道中,有一个非常好的库可以做到这一点。它被称为ngx-pipes

      例如,keys 管道返回对象的键,值管道返回对象的值:

      密钥管道

      <div *ngFor="let key of {foo: 1, bar: 2} | keys">{{key}}</div> 
      <!-- Output: 'foo' and 'bar -->
      

      值管道

      <div *ngFor="let value of {foo: 1, bar: 2} | values">{{value}}</div>
      <!-- Output: 1 and 2 -->
      

      无需创建自己的自定义管道:)

      【讨论】:

      • 很好的替代品,但问题是,如果我们可以使用像管道这样的简单代码来实现这一点,为什么还要使用外部库来实现代码的简单和平
      • 嗯...但它是一个管道?当您导入库时,它只是您的 package.json 中的一行和模块中的另外两行。另一方面,自定义管道需要一个单独的文件,其中包含大约 10-20 行代码以及模块中的导入行。我们发现在我们的项目中使用 ngx-pipes 非常容易。我们为什么要重新发明轮子? :)
      • 是的,毫无疑问,实际上它是基于意见的,您可以在这两者之间进行选择,没有一个是错误的。
      • 不要忘记,如果您编写自定义管道,则必须以及测试该自定义管道。所以这是 10-20 行管道代码,然后可能是 20-40 行测试代码来测试管道。
      【解决方案15】:

      这是一个简单的解决方案

      您可以为此使用打字稿迭代器

      import {Component} from 'angular2/core';
      declare var Symbol;
      @Component({
          selector: 'my-app',
          template:`<div>
          <h4>Iterating an Object using Typescript Symbol</h4><br>
      Object is : <p>{{obj | json}}</p>
      </div>
      ============================<br>
      Iterated object params are:
      <div *ngFor="#o of obj">
      {{o}}
      </div>
      
      `
      })
      export class AppComponent {
        public obj: any = {
          "type1": ["A1", "A2", "A3","A4"],
          "type2": ["B1"],
          "type3": ["C1"],
          "type4": ["D1","D2"]
        };
      
        constructor() {
          this.obj[Symbol.iterator] =  () => {
                let i =0;
      
                return {
                  next: () => {
                    i++;
                    return {
                        done: i > 4?true:false,
                        value: this.obj['type'+i]
                    }
                  }
                }
          };
        }
      }
      

      http://plnkr.co/edit/GpmX8g?p=info

      【讨论】:

        【解决方案16】:

        将演示类型更改为数组 或者遍历你的对象并推送到另一个数组

        public details =[];   
        Object.keys(demo).forEach(key => {
              this.details.push({"key":key,"value":demo[key]);
            });
        

        来自html:

        <div *ngFor="obj of details">
          <p>{{obj.key}}</p>
          <p>{{obj.value}}</p>
          <p></p>
        </div>
        

        【讨论】:

        • 这不是一个合适的方法,任何人都可以轻松做到。
        【解决方案17】:

        我认为 Object.keys 是解决这个问题的最佳方法。对于遇到此答案并试图找出为什么 Object.keys 给他们 ['0', '1'] 而不是 ['key1', 'key2'] 的任何人,这是一个警示故事 - 请注意“的”和“在”:

        我已经在使用 Object.keys,类似于:

        interface demo {
            key: string;
            value: string;
        }
        
        createDemo(mydemo: any): Array<demo> {
            const tempdemo: Array<demo> = [];
        
            // Caution: use "of" and not "in"
            for (const key of Object.keys(mydemo)) {
                tempdemo.push(
                    { key: key, value: mydemo[key]}
                );
            }
        
            return tempdemo;
        }
        

        但是,而不是

        for (const key OF Object.keys(mydemo)) {
        

        我不小心写了

        for (const key IN Object.keys(mydemo)) {
        

        它“工作”非常好,没有任何错误并返回

        [{key: '0', value: undefined}, {key: '1', value: undefined}]
        

        这花了我大约 2 个小时的谷歌搜索和诅咒..

        (拍脑门)

        【讨论】:

          【解决方案18】:

          你现在必须这样做,我知道效率不高,因为你不想转换从 firebase 收到的对象。

              this.af.database.list('/data/' + this.base64Email).subscribe(years => {
                  years.forEach(year => {
          
                      var localYears = [];
          
                      Object.keys(year).forEach(month => {
                          localYears.push(year[month])
                      });
          
                      year.months = localYears;
          
                  })
          
                  this.years = years;
          
              });
          

          【讨论】:

            【解决方案19】:

            您可以通过尝试获得动态对象的密钥

            myObj['key']
            

            【讨论】:

            • 你是认真的吗?
            【解决方案20】:

            像这样创建你的数组

            tags = [
                    {
                        name : 'Aliko Dogara',
                        amount   : '60,000',
                        purpose: 'Office repairs'
                    },
                    {
                        name : 'Aliko Dogara',
                        amount   : '60,000',
                        purpose: 'Office repairs'
                    },
                    {
                        name : 'Aliko Dogara',
                        amount   : '60,000',
                        purpose: 'Office repairs'
                    },
                    {
                        name : 'Aliko Dogara',
                        amount   : '60,000',
                        purpose: 'Office repairs'
                    },
                    {
                        name : 'Aliko Dogara',
                        amount   : '60,000',
                        purpose: 'Office repairs'
                    }
                ];
            

            一直有效

            【讨论】:

              猜你喜欢
              • 2020-10-23
              • 2018-07-30
              相关资源
              最近更新 更多