如何使用ngFor将Typescript枚举迭代为字符串数组


76

我正在使用Angular2和Typscript。我有一个枚举:

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

我想使用* ngFor遍历枚举。做这个的最好方式是什么?我必须创建一个管道吗?还是有更简单的方法?


请考虑更新对Murolack答案的公认答案,因为这是最简单,最新的答案。谢谢!
尤连

Answers:


81

枚举只是一个对象。

您的枚举是用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
}

因此,您可以通过以下方式进行迭代(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);
    }
}

或者创建自定义管道会更好

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

更新资料

Typescript 2.4允许枚举成员包含字符串初始化器,例如:

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

在这种情况下,您可以Object.keys(data);从管道返回。


如果包含负值,则效果不佳。顺便说一句:plnkr不再工作。
Martin Schneider

@ MA-Maddin更新的矮子
yurzui

如果有人在共享模块中使用自定义管道,请不要忘记在导出中添加EnumToArrayPipe
Rob,

2
在角度6中,您可以只返回键的数组,而不必在管道中切成一半:return Object.keys(data);
K1ngjulien_

5
实际上,在Angular 6中,您甚至不需要管道,只需role = Object.keys(Role)在组件中使用即可。
巴斯蒂安·詹森


14

模板的范围是组件实例。如果要访问此范围之外的内容,则需要通过使用组件实例使其可用:

如果枚举键不以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;
}

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


谢谢您的帮助。我刚刚尝试了此操作,但收到错误消息“ NgFor仅支持绑定到Iterables,例如数组”。因此,看起来我可以创建一个管道来将角色转换为枚举或字符串数​​组。但是在我看来,我似乎应该能够以某种方式在本地执行此操作。
罗伯·戈曼

对不起,忘了烟斗。更新了我的答案。
君特Zöchbauer

1
谢谢!比强制转换为Array更好的解决方案:-)
Axel Schmitz

我收到错误类型为'{进口的争论:(typeof EnumToArrayPipe)[]; 选择器:字符串;templateUrl:字符串; styleUrls:string []; }”不可分配给“组件”类型的参数。对象文字只能指定已知的属性,并且'imports'在'Component'类型中不存在。当我将其放在ngModule中的导入中时,它找不到管道。知道有什么问题吗?
GeekPeek

1
使用/引用管道必须使用enum(s)ToArray完成,如在管道(名称)的声明中所示。我进行了编辑。
Bernoulli IT

9

我需要做同样的事情,也许这就是您想要的。
更干燥,也可以使用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);
  }
}

切片之前的对象输出

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

打字稿合并两个声明,因此 keys.lenght-1

ngFor

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

更多信息:
Typescript的声明合并

基于:
TypeScript:向枚举添加函数 https://basarat.gitbooks.io/typescript/content/docs/enums.html(在枚举章的最后)。


1
而要获取值,您将执行相反的操作:let values = Object.keys(ApplicationMode); 返回values.slice(0,values.length / 2); 谢谢你的主意。
AFD

在切片之前没有“键”项,因此您不需要keys.lenght-1
KlsLondon

7

在进一步研究和审查了其他答案之后,我现在可以为我的问题制定答案。我认为在组件中没有某些代码支持的情况下,不可能仅使用* ngFor来遍历枚举。代码支持可以包含将Enum转换为某种数组的构造函数代码,或者我们可以创建执行类似操作的自定义管道。


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

您的角度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;
  }
}

3

我有枚举:

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

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

在HTML模板中显示以下枚举的值和键:

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

ngFor内部方法的使用将导致大量更改检测,因为无法很好地检测到函数返回值更改。您应该将“ fileVals()”返回值放入变量中,然后从那里读取它。
Nadine

3

使用管道:

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

并在模板中:

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

2

我建议您使用通用Pipe,它将在您的代码中更加灵活和减少冗余。先前的命题的问题在于,打字稿允许您使用不同种类的枚举,而不仅仅是数字/字符串。

例如:

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

这是我的解决方案:

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

和html将是:

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

在ts中:

public notificationGrouping : NotificationGrouping

注意:看到人们在不加解释的情况下放减号还是很有趣的。对于其他对此解决方案可能感兴趣的人,我可以确认它是否正确运行。


在哪里定义了notificationGrouping?
LearningPal

1
尽管起初我希望按打字稿或按角度提供一种更简单的解决方案(默认情况下将不包括任何排序),但您的解决方案是完美的,并且我今天学到了一些新东西:管道!:)非常感谢
Mihai Cicu

2

ES6支持

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

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

1

在Angular 7中,使用keys()时仍会获得所有键和值的列表。

基于以上答案,我将其用于一个简单的ENUM,看起来更干净,更OO:

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

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

然后在模板中:

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

该函数成为枚举中的另一个条目,但像其他非数字一样被过滤掉。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.