I am using Angular2 and Typscript. I have an enum:
export enum Role {
ServiceAdmin, CompanyAdmin, Foreman, AgentForeman,
CrewMember, AgentCrewMembe
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:
<mat-select [(ngModel)]="groupKey">
<mat-option *ngFor="let group of notificationGrouping | enumToArray"
[value]="group.key">
{{ group.value }}
</mat-option>
</mat-select>
in 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.
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
@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
I needed to do the same thing and maybe this is what you wanted.
More DRY and it can be used with module
too.
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
and the 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.)
In Angular 7, still getting a list of all keys and values when using keys().
Based on the above answers I am using this for a simple ENUM, seems cleaner and more 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.
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. 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.