简体   繁体   English

如何使用 ngFor 将 Typescript Enum 作为字符串数组进行迭代

[英]How can I use ngFor to iterate over Typescript Enum as an array of strings

I'm using Angular2 and TypeScript and I have an enum:我正在使用 Angular2 和 TypeScript,我有一个枚举:

export enum Role {
    ServiceAdmin, CompanyAdmin, Foreman, AgentForeman, 
    CrewMember, AgentCrewMember, Customer
}

I want to use *ngFor to iterate over the enum.我想使用 *ngFor 来迭代枚举。 What is the best way to do this?做这个的最好方式是什么? Must I create a Pipe?我必须创建一个管道吗? Or is there a simpler way?或者有没有更简单的方法?

You can just use the "keyvalue" pipe introduced in Angular 6.1.您可以只使用 Angular 6.1 中引入的“键值”管道。

<p *ngFor="let enum of TestEnum | keyvalue">
  {{ enum.key }} - {{ enum.value}}
</p>

See here for a full example -> https://stackblitz.com/edit/angular-gujg2e有关完整示例,请参见此处-> https://stackblitz.com/edit/angular-gujg2e

An enum is just an object.枚举只是一个对象。

Your enum is written something like this in JavaScript:你的枚举在 JavaScript 中是这样写的:

{
    0: "ServiceAdmin", 
    1: "CompanyAdmin", 
    2: "Foreman", 
    3: "AgentForeman", 
    4: "CrewMember", 
    5: "AgentCrewMember", 
    6: "Customer", 
    ServiceAdmin: 0, 
    CompanyAdmin: 1, 
    Foreman: 2, 
    AgentForeman: 3, 
    CrewMember: 4,
    AgentCrewMember: 5,
    Customer: 6
}

So you can iterate it this way ( plnkr ):所以你可以这样迭代它( plnkr ):

@Component({
    ...
    template: `
    <div *ngFor="let item of keys()">
      {{ item }}
    </div>  
  `
})
export class YourComponent {
    role = Role;
    keys() : Array<string> {
        var keys = Object.keys(this.role);
        return keys.slice(keys.length / 2);
    }
}

Or would be better to create custom pipe :或者更好地创建自定义管道

@Pipe({
  name: 'enumToArray'
})
export class EnumToArrayPipe implements PipeTransform {
  transform(data: Object) {
    const keys = Object.keys(data);
    return keys.slice(keys.length / 2);
  }
}

Example例子

Update更新

Typescript 2.4 allows enum members to contain string initializers like: Typescript 2.4 允许枚举成员包含字符串初始值设定项,例如:

enum Colors {
    Red = "RED",
    Green = "GREEN",
    Blue = "BLUE",
}

in this case you can just return Object.keys(data);在这种情况下,您可以只返回Object.keys(data); from pipe.从管道。

The scope of the template is the component instance.模板的范围是组件实例。 If you want to access something outside this scope you need to make it available from withing your component instance:如果你想访问这个范围之外的东西,你需要通过你的组件实例使它可用:

This also works if the enum keys do not start with 0如果枚举键不以 0 开头,这也有效

@Pipe({name: 'enumToArray'})
export class EnumToArrayPipe implements PipeTransform {
  transform(value) : Object {
    return Object.keys(value).filter(e => !isNaN(+e)).map(o => { return {index: +o, name: value[o]}});
  }
}

@Component({
  ...
  imports: [EnumsToArrayPipe],
  template: `<div *ngFor="let item of roles | enumToArray">{{item.index}}: {{item.name}}</div>`
})
class MyComponent {
  roles = Role;
}

See also https://stackoverflow.com/a/35750252/217408另请参阅https://stackoverflow.com/a/35750252/217408

I needed to do the same thing and maybe this is what you wanted.我需要做同样的事情,也许这就是你想要的。
More DRY and it can be used with module too.更干燥,它也可以与module一起使用。

export enum Role {
    ServiceAdmin, CompanyAdmin, Foreman, AgentForeman, 
    CrewMember, AgentCrewMember, Customer
}

export namespace Role {

  export function keys(): Array<string>{
    var keys = Object.keys(Role);
    return keys.slice(keys.length / 2, keys.length-1);
  }
}

the object output before the slice切片前的对象输出

{
    "1",
    "2",
    "3",
    "4",
    "5",
    "6",
    "7",
    "ServiceAdmin",
    "CompanyAdmin",
    "Foreman",
    "AgentForeman",
    "CrewMember",
    "AgentCrewMember",
    "Customer",
    "keys"
}

typescript merges the two declarations hence the keys.lenght-1打字稿合并这两个声明,因此keys.lenght-1

and the ngFor :ngFor

<div *ngFor="let role of Roles.keys()">{{ role }}</div>

more info:更多信息:
Typescript's Declaration merging 打字稿的声明合并

based on:基于:
TypeScript: Add functions to an Enum https://basarat.gitbooks.io/typescript/content/docs/enums.html (at the end of the enums chapter.) TypeScript:向枚举添加函数https://basarat.gitbooks.io/typescript/content/docs/enums.html (在枚举章节的末尾。)

After further research and review of the other answers I now can formulate an answer to my question.在进一步研究和审查其他答案之后,我现在可以为我的问题制定一个答案。 I think its not possible to just use *ngFor to iterate over an enum without some code support in the component.我认为在组件中没有一些代码支持的情况下,仅使用 *ngFor 来迭代枚举是不可能的。 The code support can consist of constructor code that turns the Enum into some sort of array or we can create a custom pipe that does something similar.代码支持可以包含将 Enum 转换为某种数组的构造函数代码,或者我们可以创建一个执行类似操作的自定义管道。

export enum Priority {
  LL = 1,   // VERY LOW
  L = 2,    // LOW
  N = 3,    // NORMAL
  U = 4,    // HIGH
  UU = 5    // VERY HIGH
}

Your angular component.ts :你的角度 component.ts :

import { Priority } from './../shared/core/config/datas.config';

@Component({
  selector: 'app-yourcomponent',
  template: `
    <ng-container *ngFor="let p of getPriority">
       <div> {{p.key}} / {{p.value}} </div>
    </ng-container> 
  `
})

export class YourComponent {
  getPriority = this.getENUM(Priority);

  getENUM(ENUM:any): string[] {
    let myEnum = [];
    let objectEnum = Object.keys(ENUM);
    const values = objectEnum.slice( 0 , objectEnum.length / 2 );
    const keys = objectEnum.slice( objectEnum.length / 2 );

    for (let i = 0 ; i < objectEnum.length/2 ; i++ ) {
      myEnum.push( { key: keys[i], value: values[i] } ); 
    }
    return myEnum;
  }
}

using pipe:使用管道:

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

@Pipe({
  name: 'enum'
})
export class EnumSelectPipe implements PipeTransform {
  transform(value: any): [number, string][] {
    return Object.keys(value).filter(t => isNaN(+t)).map(t => [value[t], t]);
  }
}

and in the template:并在模板中:

<mat-select formControlName="type" placeholder="Package Type">
  <mat-option *ngFor="let pType of PackageTypes | enum" [value]="pType[0]">{{ pType[1] | title}}</mat-option>
</mat-select>

I have the enum:我有枚举:

export enum FileCategory {
  passport = 'Multipass',
  agreement = 'Personal agreement',
  contract = 'Contract',
  photo = 'Self photos',
  other = 'Other'
}

In the component ts file:在组件 ts 文件中:

export class MyBestComponent implements OnInit {
  fileCategory = FileCategory;

  // returns keys of enum
  fileKeys(): Array<string> {
    const keys = Object.keys(this.fileCategory);
    return keys;
  }

  // returns values of enum
  fileVals(): Array<string> {
    const keys = Object.keys(this.fileCategory);
    return keys.map(el => Object(this.fileCategory)[el]);
  }

In the HTML template display these enum's values and keys:在 HTML 模板中显示这些枚举的值和键:

  <a *ngFor="let cat of fileVals()"
     (click)="addFileCategory(cat)">{{cat}}</a>
  <a *ngFor="let cat of fileKeys()"
     (click)="addFileCategory(cat)">{{cat}}</a>

I recommend you to use a generic Pipe, it will be more flexible and less redundant in your code.我建议您使用通用管道,它会更灵活且代码中的冗余更少。 The problem with some previous propositions is that the typescript allow you to have different kind of enum, not only number/string.以前的一些命题的问题是打字稿允许您拥有不同类型的枚举,而不仅仅是数字/字符串。

For example:例如:

export enum NotificationGrouping {
    GroupByCreatedAt = "GroupByCreatedAt", 
    GroupByCreatedByUser = "GroupByCreatedByUser", 
    GroupByEntity = "GroupByEntity", 
    GroupByAction = "GroupByAction", 
}

Here is my solution:这是我的解决方案:

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

@Pipe({
    name: 'enumToArray'
})
export class EnumToArrayPipe implements PipeTransform {

  transform(value, args: string[]): any {
    let result = [];
    var keys = Object.keys(value);
    var values = Object.values(value);
    for (var i = 0; i < keys.length; i++) {
      result.push({ key: keys[i], value: values[i] });
    }
    return result; 
    //or if you want to order the result: 
    //return result.sort((a, b) => a.value < b.value ? -1 : 1);
  }
}

and the html will be: html 将是:

<mat-select [(ngModel)]="groupKey">
  <mat-option *ngFor="let group of notificationGrouping | enumToArray"
              [value]="group.key">
    {{ group.value }}
  </mat-option>
</mat-select>

in ts:在 ts 中:

public notificationGrouping : NotificationGrouping

Note: Still interesting to see people putting a minus without explanation ... For others who could be interested by this solution, I can confirm that it works correctly.注意:看到人们在没有解释的情况下加上减号仍然很有趣......对于其他可能对此解决方案感兴趣的人,我可以确认它可以正常工作。

ES6 supports ES6支持

export enum E {
    a = 'First',
    b = 'Second',
    c = 'Third'
}

let keyValueArray = Object.keys(E).map(k => ({key: k, value: E[k as any]}));

In Angular 7, still getting a list of all keys and values when using keys().在 Angular 7 中,使用 keys() 时仍会获取所有键和值的列表。

Based on the above answers I am using this for a simple ENUM, seems cleaner and more OO:基于上述答案,我将其用于简单的 ENUM,看起来更干净,更 OO:

export enum CategoryType {
    Type1,
    Type2,
    ...,
}

export namespace CategoryType {
    export function keys() {
        return Object.keys(CategoryType).filter(k => !isNaN(Number(k)));
    }
}

then in the template:然后在模板中:

<option *ngFor="let type of types.keys()" [value]="type">{{types[type]}}</option>

The function becomes another entry in the enum, but gets filtered out like the other non-numbers.该函数成为枚举中的另一个条目,但像其他非数字一样被过滤掉。

 fillKeysValueFromEnum<T>(type:T){
    return Object.keys(type).filter(t => isNaN(+t)).map(el => {
       return {
         key: el,
         value: Object(type)[el]
       }
     });
  }

Then然后

fillKeysValueFromEnum(ENUM_HERE)

I am very late to it and my answer might not directly solve the question but it gets the job done.我已经很晚了,我的回答可能无法直接解决问题,但可以完成工作。 Today I came across a ask which revolved around the same problem, ie, iterating enum .今天我遇到了一个围绕同一问题的问题,即迭代enum

I took to creating a object instead of using enum .我开始创建一个object而不是使用enum

export const Roles= {
    0: "ServiceAdmin", 1: "CompanyAdmin", 2: "Foreman", 3: "AgentForeman", 
    4: "CrewMember", 5: "AgentCrewMember", 6: "Customer"
}

To iterate use like below:迭代使用如下:

let Number=Number; 
let roles= Roles; // in .ts file
<select>
    <option *ngFor="let role of roles | keyvalue" [value]="Number({{role.key}})">
        {{role.value}}
    </option>
</select>

To parse a value use like below:要解析一个值,如下所示:

let selectedRoleValue= 4; 
let Roles= Roles; // in .ts file

<div>{{Roles[selectedRoleValue]}}</div>

This will display这将显示

CrewMember船员

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM