Typescript枚举看起来和Angular2的ngSwitch指令很匹配。但是当我试图在我的组件的模板中使用枚举时,我得到“无法读取属性'xxx'的未定义在…”如何在组件模板中使用枚举值?

请注意,这与如何基于枚举(ngFor)的所有值创建html选择选项不同。这个问题是关于基于枚举的特定值的ngSwitch。尽管出现了创建枚举的类内部引用的相同方法。


当前回答

首先考虑“我真的想做这件事吗?”

我在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开关)。这也可能在未来的更新中得到改进。

其他回答

你可以在你的组件类中创建一个对枚举的引用(我只是将初始字符改为小写),然后从模板(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;
  }
}

Angular4 -在HTML模板中使用Enum

解决方案: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>

首先考虑“我真的想做这件事吗?”

我在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 "

您可以创建一个自定义装饰器,添加到组件中,使其能够识别枚举。

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;
}

enum-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;
  }
}