Typescript 枚举似乎与 Angular2 的 ngSwitch 指令自然匹配。但是当我尝试在我的组件模板中使用枚举时,我得到“无法读取...中未定义的属性'xxx'”。如何在组件模板中使用枚举值?
请注意,这与如何根据枚举 (ngFor) 的所有值创建 html 选择选项不同。这个问题是关于 ngSwitch 基于枚举的特定值。尽管出现了创建对枚举的类内部引用的相同方法。
您可以在组件类中创建对枚举的引用(我只是将初始字符更改为小写),然后使用模板中的该引用 (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;
}
}
这很简单,就像一个魅力:) 只需像这样声明你的枚举,你就可以在 HTML 模板上使用它
statusEnum: typeof StatusEnum = StatusEnum;
您可以创建一个自定义装饰器以添加到您的组件中,以使其了解枚举。
myenum.enum.ts:
export enum MyEnum {
FirstValue,
SecondValue
}
myenumaware.decorator.ts
import { MyEnum } from './myenum.enum';
export function MyEnumAware(constructor: Function) {
constructor.prototype.MyEnum = MyEnum;
}
枚举-aware.component.ts
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
的含义,它是 Angular 的核心类知道如何与之交互的空类的扩展。
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 / 最终
...
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"
此示例使用服务获取当前布局,通过异步管道运行它,然后将其与我们的枚举值进行比较。它非常冗长,令人费解,而且看起来并不有趣。它还公开了枚举的名称,它本身可能过于冗长。
替代方案,它保留了 HTML 的类型安全性
或者,您可以执行以下操作,并在组件的 .ts 文件中声明更具可读性的函数:
*ngIf="isResponsiveLayout('Horizontal')"
干净多了!但是如果有人错误地输入了 'Horziontal'
怎么办?您想在 HTML 中使用枚举的全部原因是类型安全,对吧?
我们仍然可以使用 keyof 和一些 typescript 魔术来实现这一点。这是函数的定义:
isResponsiveLayout(value: keyof typeof FeatureBoxResponsiveLayout)
{
return FeatureBoxResponsiveLayout[value] == this.featureBoxResponsiveService.layout.value;
}
注意 FeatureBoxResponsiveLayout[string]
的用法,其中 converts 将字符串值传递给枚举的数值。
如果您使用无效值,这将在 AOT 编译中给出错误消息。
'"H4orizontal"' 类型的参数不可分配给 '"Vertical" 类型的参数 | “水平的”
目前 VSCode 不够聪明,无法在 HTML 编辑器中为 H4orizontal
下划线,但您会在编译时收到警告(使用 --prod build 或 --aot 开关)。这也可能在未来的更新中得到改进。
html
中的常量,但我明白你的意思并开始使用它;它在编译时完成了工作,就像过去的美好时光一样! :)
我的组件使用了类型为 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>
如果使用“类型表引用”方法(来自@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 回答所示那样提供服务)。如果你有很多很多类型表,这可能会变得很麻烦。
此外,您总是在声明中重命名它们以获得更短的名称。
您现在可以这样做:
例如,枚举是:
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 MessagePriority”类型声明给类,然后通过调用“this.messagePriority = MessagePriority”定义绑定到类
StatusEnum
在.ts
类之一中定义。在您导入的 Angular 组件中,将其绑定到组件属性(此处为statusEnum
),并且可以从模板访问组件属性。