Typescript枚举似乎与Angular2的ngSwitch指令自然匹配。但是,当我尝试在组件模板中使用枚举时,出现“无法读取...中未定义的属性'xxx'”。如何在组件模板中使用枚举值?
请注意,这与基于枚举(ngFor)的所有值创建html select选项的方式不同。这个问题是关于基于特定枚举值的ngSwitch的。尽管出现了创建对枚举的类内部引用的相同方法。
Typescript枚举似乎与Angular2的ngSwitch指令自然匹配。但是,当我尝试在组件模板中使用枚举时,出现“无法读取...中未定义的属性'xxx'”。如何在组件模板中使用枚举值?
请注意,这与基于枚举(ngFor)的所有值创建html select选项的方式不同。这个问题是关于基于特定枚举值的ngSwitch的。尽管出现了创建对枚举的类内部引用的相同方法。
Answers:
您可以在组件类中创建对枚举的引用(我只是将初始字符更改为小写),然后从模板(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;
}
}
您可以创建一个自定义装饰器以添加到您的组件中,以使其了解枚举。
export enum MyEnum {
FirstValue,
SecondValue
}
import { MyEnum } from './myenum.enum';
export function MyEnumAware(constructor: Function) {
constructor.prototype.MyEnum = MyEnum;
}
import { Component } from '@angular2/core';
import { MyEnum } from './myenum.enum';
import { MyEnumAware } from './myenumaware.decorator';
@Component({
selector: 'enum-aware',
template: `
<div [ngSwitch]="myEnumValue">
<div *ngSwitchCase="MyEnum.FirstValue">
First Value
</div>
<div *ngSwitchCase="MyEnum.SecondValue">
Second Value
</div>
</div>
<button (click)="toggleValue()">Toggle Value</button>
`,
})
@MyEnumAware // <---------------!!!
export default class EnumAwareComponent {
myEnumValue: MyEnum = MyEnum.FirstValue;
toggleValue() {
this.myEnumValue = this.myEnumValue === MyEnum.FirstValue
? MyEnum.SecondValue : MyEnum.FirstValue;
}
}
MyEnumAware()
,EnumAwareComponent
实例在此处传递,并MyEnum
在其原型中添加了属性。该属性的值是设置枚举本身。此方法与接受的答案具有相同的作用。它只是利用为装饰器建议的语法糖,并在TypeScript中允许使用。使用Angular时,您马上就使用了装饰器语法。这是一个什么Component
是,空类的扩展角的核心类知道如何与互动。
ERROR in ng:///.../whatever.component.html (13,3): Property 'MyEnum' does not exist on type 'EnumAwareComponent'
。这是有道理的,因为从未声明装饰器添加的属性,而使打字稿编译器不知道其存在。
--prod
构建(Ionic 3 / Angular 4 / Typescript 2.4.2),它不再起作用。我得到了错误"TypeError: Cannot read property 'FirstValue' of undefined"
。我正在使用标准的数字枚举。它与AoT兼容,但不适用于--prod
。如果我将其更改为在HTML中使用整数,它确实可以工作,但这不是重点。有任何想法吗?
Angular4-在HTML模板ngSwitch / ngSwitchCase中使用枚举
解决方案在这里:https : //stackoverflow.com/a/42464835/802196
信用:@snorkpete
在组件中,您有
enum MyEnum{
First,
Second
}
然后在组件中,通过成员'MyEnum'引入Enum类型,并为枚举变量'myEnumVar'创建另一个成员:
export class MyComponent{
MyEnum = MyEnum;
myEnumVar:MyEnum = MyEnum.Second
...
}
现在,您可以在.html模板中使用myEnumVar和MyEnum。例如,在ngSwitch中使用枚举:
<div [ngSwitch]="myEnumVar">
<div *ngSwitchCase="MyEnum.First"><app-first-component></app-first-component></div>
<div *ngSwitchCase="MyEnum.Second"><app-second-component></app-second-component></div>
<div *ngSwitchDefault>MyEnumVar {{myEnumVar}} is not handled.</div>
</div>
截至rc.6 / final
...
export enum AdnetNetworkPropSelector {
CONTENT,
PACKAGE,
RESOURCE
}
<div style="height: 100%">
<div [ngSwitch]="propSelector">
<div *ngSwitchCase="adnetNetworkPropSelector.CONTENT">
<AdnetNetworkPackageContentProps [setAdnetContentModels]="adnetNetworkPackageContent.selectedAdnetContentModel">
</AdnetNetworkPackageContentProps>
</div>
<div *ngSwitchCase="adnetNetworkPropSelector.PACKAGE">
</div>
</div>
</div>
export class AdnetNetwork {
private adnetNetworkPropSelector = AdnetNetworkPropSelector;
private propSelector = AdnetNetworkPropSelector.CONTENT;
}
作为@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>
我在HTML中直接引用枚举没有问题,但是在某些情况下,还有一些更干净的替代方案不会丢失类型安全性。例如,如果您选择我的其他答案中所示的方法,则可能已在组件中声明了TT,如下所示:
public TT =
{
// Enum defines (Horizontal | Vertical)
FeatureBoxResponsiveLayout: FeatureBoxResponsiveLayout
}
要在HTML中显示不同的布局,您需要*ngIf
为每种布局类型提供一个,并且可以直接引用组件HTML中的枚举:
*ngIf="(featureBoxResponsiveService.layout | async) == TT.FeatureBoxResponsiveLayout.Horizontal"
本示例使用服务获取当前布局,通过异步管道运行它,然后将其与我们的枚举值进行比较。它很冗长,令人费解,看起来也没有太多乐趣。它还暴露了枚举的名称,该名称本身可能过于冗长。
另外,您可以执行以下操作,并在组件的.ts文件中声明一个更具可读性的函数:
*ngIf="isResponsiveLayout('Horizontal')"
干净得多!但是,如果有人'Horziontal'
错误输入怎么办?您想要在HTML中使用枚举的全部原因是类型安全的,对吧?
我们仍然可以使用keyof和一些打字稿魔术来实现。这是函数的定义:
isResponsiveLayout(value: keyof typeof FeatureBoxResponsiveLayout)
{
return FeatureBoxResponsiveLayout[value] == this.featureBoxResponsiveService.layout.value;
}
需要注意的使用FeatureBoxResponsiveLayout[string]
,其转换传递给枚举的数值的字符串值。
如果您使用无效的值,这将在AOT编译中给出错误消息。
类型'“ H4orizontal”'的参数不能分配给类型'“ Vertical” |的参数。“水平”
当前,VSCode不够智能,无法H4orizontal
在HTML编辑器中加下划线,但是您会在编译时收到警告(使用--prod build或--aot开关)。在将来的更新中可能还会对此进行改进。
html
但是我明白了你的观点并开始使用它;就像过去的美好时光一样,它可以完成工作!:)
我的组件使用了本身正在使用myClassObject
的类型的对象。这导致上述相同的问题。通过执行以下操作解决了该问题:MyClass
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>
如果使用“类型表引用”方法(来自@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;
然后使用
{{ TT.DogType[dog] }} => "GoldenRetriever"
我喜欢这种方法,因为它可以清楚地表明您在引用一个类型表,还可以避免不必要地污染组件文件。
您还可以将全局TT
变量放置在某个位置,并根据需要向其添加枚举(如果需要,您也可以提供@VincentSels答案所示的服务)。如果您有许多类型表,这可能会变得很麻烦。
同样,您总是在声明中重命名它们以获得较短的名称。