我如何使用 ngFor 将 Typescript Enum 作为字符串数组进行迭代
How can I use ngFor to iterate over Typescript Enum as an array of strings
我正在使用 Angular2 和 TypeScript,我有一个枚举:
export enum Role {
ServiceAdmin, CompanyAdmin, Foreman, AgentForeman,
CrewMember, AgentCrewMember, Customer
}
我想使用 *ngFor 遍历枚举。做这个的最好方式是什么?我必须创建一个管道吗?或者有更简单的方法吗?
模板的范围是组件实例。如果你想访问这个范围之外的东西,你需要让它在你的组件实例中可用:
如果枚举键不以 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;
}
另见
枚举只是一个对象。
你的枚举在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",
}
在这种情况下,您可以 return Object.keys(data);
来自管道。
经过进一步研究和审查其他答案后,我现在可以制定我的问题的答案。我认为如果组件中没有一些代码支持,就不可能只使用 *ngFor 来迭代枚举。代码支持可以包含将 Enum 转换为某种数组的构造函数代码,或者我们可以创建一个执行类似操作的自定义管道。
我需要做同样的事情,也许这就是你想要的。
更多 DRY,它也可以与 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"
}
typescript 合并了两个声明,因此 keys.lenght-1
和 ngFor
:
<div *ngFor="let role of Roles.keys()">{{ role }}</div>
更多信息:
Typescript's Declaration merging
基于:
https://basarat.gitbooks.io/typescript/content/docs/enums.html(在 enums 章节的末尾。)
我有枚举:
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>
export enum Priority {
LL = 1, // VERY LOW
L = 2, // LOW
N = 3, // NORMAL
U = 4, // HIGH
UU = 5 // VERY HIGH
}
你的 angular 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;
}
}
在Angular 7中,使用keys()时仍然得到所有键和值的列表。
基于以上答案,我将其用于简单的 ENUM,看起来更干净,更面向对象:
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>
该函数成为枚举中的另一个条目,但像其他非数字一样被过滤掉。
我建议你使用通用的管道,它会更灵活,代码冗余更少。
以前的一些命题的问题是打字稿允许你有不同种类的枚举,而不仅仅是 number/string.
例如:
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
注意:看到人们在没有解释的情况下加上减号仍然很有趣......对于可能对此解决方案感兴趣的其他人,我可以确认它可以正常工作。
您可以只使用 Angular 6.1 中引入的“键值”管道。
<p *ngFor="let enum of TestEnum | keyvalue">
{{ enum.key }} - {{ enum.value}}
</p>
完整示例请参见此处 ->
https://stackblitz.com/edit/angular-gujg2e
使用管道:
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>
ES6支持
export enum E {
a = 'First',
b = 'Second',
c = 'Third'
}
let keyValueArray = Object.keys(E).map(k => ({key: k, value: E[k as any]}));
fillKeysValueFromEnum<T>(type:T){
return Object.keys(type).filter(t => isNaN(+t)).map(el => {
return {
key: el,
value: Object(type)[el]
}
});
}
然后
fillKeysValueFromEnum(ENUM_HERE)
我来晚了,我的回答可能不会直接解决问题,但它完成了工作。今天我遇到了一个围绕相同问题的问题,即迭代 enum
.
我开始创建 object
而不是使用 enum
。
export const Roles= {
0: "ServiceAdmin", 1: "CompanyAdmin", 2: "Foreman", 3: "AgentForeman",
4: "CrewMember", 5: "AgentCrewMember", 6: "Customer"
}
迭代使用如下:
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>
要像下面这样解析一个值:
let selectedRoleValue= 4;
let Roles= Roles; // in .ts file
<div>{{Roles[selectedRoleValue]}}</div>
这将显示
CrewMember
我正在使用 Angular2 和 TypeScript,我有一个枚举:
export enum Role {
ServiceAdmin, CompanyAdmin, Foreman, AgentForeman,
CrewMember, AgentCrewMember, Customer
}
我想使用 *ngFor 遍历枚举。做这个的最好方式是什么?我必须创建一个管道吗?或者有更简单的方法吗?
模板的范围是组件实例。如果你想访问这个范围之外的东西,你需要让它在你的组件实例中可用:
如果枚举键不以 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;
}
另见
枚举只是一个对象。
你的枚举在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",
}
在这种情况下,您可以 return Object.keys(data);
来自管道。
经过进一步研究和审查其他答案后,我现在可以制定我的问题的答案。我认为如果组件中没有一些代码支持,就不可能只使用 *ngFor 来迭代枚举。代码支持可以包含将 Enum 转换为某种数组的构造函数代码,或者我们可以创建一个执行类似操作的自定义管道。
我需要做同样的事情,也许这就是你想要的。
更多 DRY,它也可以与 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"
}
typescript 合并了两个声明,因此 keys.lenght-1
和 ngFor
:
<div *ngFor="let role of Roles.keys()">{{ role }}</div>
更多信息:
Typescript's Declaration merging
基于:
我有枚举:
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>
export enum Priority {
LL = 1, // VERY LOW
L = 2, // LOW
N = 3, // NORMAL
U = 4, // HIGH
UU = 5 // VERY HIGH
}
你的 angular 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;
}
}
在Angular 7中,使用keys()时仍然得到所有键和值的列表。
基于以上答案,我将其用于简单的 ENUM,看起来更干净,更面向对象:
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>
该函数成为枚举中的另一个条目,但像其他非数字一样被过滤掉。
我建议你使用通用的管道,它会更灵活,代码冗余更少。 以前的一些命题的问题是打字稿允许你有不同种类的枚举,而不仅仅是 number/string.
例如:
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
注意:看到人们在没有解释的情况下加上减号仍然很有趣......对于可能对此解决方案感兴趣的其他人,我可以确认它可以正常工作。
您可以只使用 Angular 6.1 中引入的“键值”管道。
<p *ngFor="let enum of TestEnum | keyvalue">
{{ enum.key }} - {{ enum.value}}
</p>
完整示例请参见此处 -> https://stackblitz.com/edit/angular-gujg2e
使用管道:
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>
ES6支持
export enum E {
a = 'First',
b = 'Second',
c = 'Third'
}
let keyValueArray = Object.keys(E).map(k => ({key: k, value: E[k as any]}));
fillKeysValueFromEnum<T>(type:T){
return Object.keys(type).filter(t => isNaN(+t)).map(el => {
return {
key: el,
value: Object(type)[el]
}
});
}
然后
fillKeysValueFromEnum(ENUM_HERE)
我来晚了,我的回答可能不会直接解决问题,但它完成了工作。今天我遇到了一个围绕相同问题的问题,即迭代 enum
.
我开始创建 object
而不是使用 enum
。
export const Roles= {
0: "ServiceAdmin", 1: "CompanyAdmin", 2: "Foreman", 3: "AgentForeman",
4: "CrewMember", 5: "AgentCrewMember", 6: "Customer"
}
迭代使用如下:
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>
要像下面这样解析一个值:
let selectedRoleValue= 4;
let Roles= Roles; // in .ts file
<div>{{Roles[selectedRoleValue]}}</div>
这将显示
CrewMember