Typescript枚举看起来和Angular2的ngSwitch指令很匹配。但是当我试图在我的组件的模板中使用枚举时,我得到“无法读取属性'xxx'的未定义在…”如何在组件模板中使用枚举值?
请注意,这与如何基于枚举(ngFor)的所有值创建html选择选项不同。这个问题是关于基于枚举的特定值的ngSwitch。尽管出现了创建枚举的类内部引用的相同方法。
Typescript枚举看起来和Angular2的ngSwitch指令很匹配。但是当我试图在我的组件的模板中使用枚举时,我得到“无法读取属性'xxx'的未定义在…”如何在组件模板中使用枚举值?
请注意,这与如何基于枚举(ngFor)的所有值创建html选择选项不同。这个问题是关于基于枚举的特定值的ngSwitch。尽管出现了创建枚举的类内部引用的相同方法。
当前回答
我的组件使用MyClass类型的对象myClassObject,它本身使用MyEnum。这导致了上面描述的相同问题。解决方法是:
export enum MyEnum {
Option1,
Option2,
Option3
}
export class MyClass {
myEnum: typeof MyEnum;
myEnumField: MyEnum;
someOtherField: string;
}
然后在模板中使用这个
<div [ngSwitch]="myClassObject.myEnumField">
<div *ngSwitchCase="myClassObject.myEnum.Option1">
Do something for Option1
</div>
<div *ngSwitchCase="myClassObject.myEnum.Option2">
Do something for Option2
</div>
<div *ngSwitchCase="myClassObject.myEnum.Option3">
Do something for Opiton3
</div>
</div>
其他回答
你可以在你的组件类中创建一个对枚举的引用(我只是将初始字符改为小写),然后从模板(plunker)中使用该引用:
import {Component} from 'angular2/core';
enum CellType {Text, Placeholder}
class Cell {
constructor(public text: string, public type: CellType) {}
}
@Component({
selector: 'my-app',
template: `
<div [ngSwitch]="cell.type">
<div *ngSwitchCase="cellType.Text">
{{cell.text}}
</div>
<div *ngSwitchCase="cellType.Placeholder">
Placeholder
</div>
</div>
<button (click)="setType(cellType.Text)">Text</button>
<button (click)="setType(cellType.Placeholder)">Placeholder</button>
`,
})
export default class AppComponent {
// Store a reference to the enum
cellType = CellType;
public cell: Cell;
constructor() {
this.cell = new Cell("Hello", CellType.Text)
}
setType(type: CellType) {
this.cell.type = type;
}
}
如果使用“typetable reference”方法(来自@Carl G),并且你正在使用多个类型表,你可能会考虑这样做:
export default class AppComponent {
// Store a reference to the enums (must be public for --AOT to work)
public TT = {
CellType: CellType,
CatType: CatType,
DogType: DogType
};
...
dog = DogType.GoldenRetriever;
然后在html文件中访问
{{ TT.DogType[dog] }} => "GoldenRetriever"
我喜欢这种方法,因为它清楚地表明您引用的是一个类型表,而且还避免了对组件文件的不必要污染。
你也可以在某个地方放置一个全局TT,并根据需要添加枚举(如果你想这样做,你也可以像@VincentSels answer所示的那样创建一个服务)。如果你有很多很多的类型,这可能会变得很麻烦。
此外,您总是在声明中重命名它们以获得更短的名称。
首先考虑“我真的想做这件事吗?”
我在HTML中直接引用枚举没有问题,但在某些情况下,有更干净的替代方案,不会失去类型安全性。 例如,如果你选择在我的其他回答中显示的方法,你可能已经在你的组件中声明了TT,就像这样:
public TT =
{
// Enum defines (Horizontal | Vertical)
FeatureBoxResponsiveLayout: FeatureBoxResponsiveLayout
}
要在HTML中显示不同的布局,你需要为每种布局类型使用*ngIf,并且你可以直接引用组件HTML中的枚举:
*ngIf="(featureBoxResponsiveService.layout | async) == TT.FeatureBoxResponsiveLayout.Horizontal"
这个例子使用一个服务来获取当前布局,通过async管道运行它,然后将它与我们的enum值进行比较。它相当啰嗦,令人费解,看起来也没什么意思。它还公开枚举的名称,该名称本身可能过于详细。
另一种选择是保留HTML的类型安全性
或者你也可以这样做,并在组件的.ts文件中声明一个更可读的函数:
*ngIf="isResponsiveLayout('Horizontal')"
多干净!但如果有人不小心输入了“水平”呢?在HTML中使用枚举的全部原因是为了类型安全,对吧?
我们仍然可以通过keyof和一些typescript魔法来实现这一点。这是函数的定义:
isResponsiveLayout(value: keyof typeof FeatureBoxResponsiveLayout)
{
return FeatureBoxResponsiveLayout[value] == this.featureBoxResponsiveService.layout.value;
}
注意使用FeatureBoxResponsiveLayout[string]将传入的字符串值转换为enum的数值。
如果使用了无效值,这将给出带有AOT编译的错误消息。
类型为“h4horizontal”的参数不能赋值给类型为“Vertical”的参数|“Horizontal”
目前VSCode还不够智能,不能在HTML编辑器中下划线h4horizont,但是你会在编译时得到警告(使用——prod build或——aot开关)。这也可能在未来的更新中得到改进。
你现在可以这样做:
例如,枚举为:
export enum MessagePriority {
REGULAR= 1,
WARNING,
IMPORTANT,
}
一个状态消息,看起来像这样:
export default class StatusMessage{
message: string;
priority: MessagePriority;
constructor(message: string, priority: MessagePriority){
this.message = message;
this.priority = priority;
}
}
然后在组件的.ts文件中,你可以这样做:
import StatusMessage from '../../src/entities/building/ranch/administration/statusMessage';
import { MessagePriority } from '../../enums/message-priority';
export class InfoCardComponent implements OnInit {
messagePriority: typeof MessagePriority;
constructor() {
this.messagePriority = MessagePriority;
}
@Input() statusMessage: StatusMessage;
ngOnInit(): void {}
}
最后这个组件的HTML是这样的:
<div class="info-card" [ngSwitch]="statusMessage.priority">
<h2 *ngSwitchCase="this.messagePriority.REGULAR" class="info-card__regular-message">{{statusMessage.message}}</h2>
<h2 *ngSwitchCase="this.messagePriority.WARNING" class="info-card__warning-message">{{statusMessage.message}}</h2>
<h2 *ngSwitchCase="this.messagePriority.IMPORTANT" class="info-card__important-message">{{statusMessage.message}}</h2>
</div>
注意,枚举首先用“typeof messagpriority”类型声明给类,然后用“this”调用定义来绑定到类。messagpriority = messagpriority "
作为@Eric Lease的装饰器(不幸的是,它不能使用——aot(因此也不能使用——prod)构建)的替代方案,我求助于使用一个公开应用程序所有枚举的服务。只需要公开地将它注入到每个需要它的组件中,在一个简单的名称下,之后你可以在视图中访问枚举。例如:
服务
import { Injectable } from '@angular/core';
import { MyEnumType } from './app.enums';
@Injectable()
export class EnumsService {
MyEnumType = MyEnumType;
// ...
}
不要忘记将它包含在模块的提供者列表中。
组件类
export class MyComponent {
constructor(public enums: EnumsService) {}
@Input() public someProperty: MyEnumType;
// ...
}
html组件
<div *ngIf="someProperty === enums.MyEnumType.SomeValue">Match!</div>