简体   繁体   English

如何在 Angular2 ngSwitch 语句中使用打字稿枚举值

[英]How to use a typescript enum value in an Angular2 ngSwitch statement

The Typescript enum seems a natural match with Angular2's ngSwitch directive. Typescript 枚举似乎与 Angular2 的 ngSwitch 指令自然匹配。 But when I try to use an enum in my component's template, I get "Cannot read property 'xxx' of undefined in ...".但是当我尝试在我的组件模板中使用枚举时,我得到“无法读取属性 'xxx' of undefined in ...”。 How can I use enum values in my component template?如何在组件模板中使用枚举值?

Please note that this is different from how to create html select options based upon ALL of the values of an enum (ngFor).请注意,这与如何根据枚举 (ngFor) 的所有值创建 html 选择选项不同。 This question is about ngSwitch based upon a particular value of an enum.这个问题是关于基于枚举的特定值的 ngSwitch。 Although the same approach of creating an class-internal reference to the enum appears.尽管出现了创建对枚举的类内部引用的相同方法。

You can create a reference to the enum in your component class (I just changed the initial character to be lower-case) and then use that reference from the template ( plunker ):您可以在组件类中创建对枚举的引用(我只是将初始字符更改为小写),然后使用模板中的引用( 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;
  }
}

You can create a custom decorator to add to your component to make it aware of enums.您可以创建一个自定义装饰器来添加到您的组件中,以使其了解枚举。

myenum.enum.ts: myenum.enum.ts:

export enum MyEnum {
    FirstValue,
    SecondValue
}

myenumaware.decorator.ts myenumaware.decorator.ts

import { MyEnum } from './myenum.enum';

export function MyEnumAware(constructor: Function) {
    constructor.prototype.MyEnum = MyEnum;
}

enum-aware.component.ts枚举感知.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;
  }
}

这很简单,就像一个魅力:) 只需像这样声明你的枚举,你就可以在 HTML 模板上使用它

  statusEnum: typeof StatusEnum = StatusEnum;

Angular4 - Using Enum in HTML Template ngSwitch / ngSwitchCase Angular4 - 在 HTML 模板 ngSwitch / ngSwitchCase 中使用枚举

Solution here: https://stackoverflow.com/a/42464835/802196解决方法在这里: https : //stackoverflow.com/a/42464835/802196

credit: @snorkpete信用:@snorkpete

In your component, you have在您的组件中,您有

enum MyEnum{
  First,
  Second
}

Then in your component, you bring in the Enum type via a member 'MyEnum', and create another member for your enum variable 'myEnumVar' :然后在您的组件中,您通过成员 'MyEnum' 引入 Enum 类型,并为您的枚举变量 'myEnumVar' 创建另一个成员:

export class MyComponent{
  MyEnum = MyEnum;
  myEnumVar:MyEnum = MyEnum.Second
  ...
}

You can now use myEnumVar and MyEnum in your .html template.您现在可以在 .html 模板中使用 myEnumVar 和 MyEnum。 Eg, Using Enums in ngSwitch:例如,在 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>

as of rc.6 / final从 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;
}

As an alternative to @Eric Lease's decorator, which unfortunately doesn't work using --aot (and thus --prod ) builds, I resorted to using a service which exposes all my application's enums.作为@Eric Lease 装饰器的替代方案,不幸的是,它不能使用--aot (因此--prod )构建,我求助于使用暴露我所有应用程序枚举的服务。 Just need to publicly inject that into each component which requires it, under an easy name, after which you can access the enums in your views.只需要以一个简单的名称将其公开注入到需要它的每个组件中,然后您就可以访问视图中的枚举。 Eg:例如:

Service服务

import { Injectable } from '@angular/core';
import { MyEnumType } from './app.enums';

@Injectable()
export class EnumsService {
  MyEnumType = MyEnumType;
  // ...
}

Don't forget to include it in your module's provider list.不要忘记将其包含在模块的提供程序列表中。

Component class组件类

export class MyComponent {
  constructor(public enums: EnumsService) {}
  @Input() public someProperty: MyEnumType;

  // ...
}

Component html组件html

<div *ngIf="someProperty === enums.MyEnumType.SomeValue">Match!</div>

Start by considering 'Do I really want to do this?'首先考虑“我真的想这样做吗?”

I have no problem referring to enums directly in HTML, but in some cases there are cleaner alternatives that don't lose type-safe-ness.我在 HTML 中直接引用枚举没有问题,但在某些情况下,有更干净的替代方案,不会失去类型安全性。 For instance if you choose the approach shown in my other answer, you may have declared TT in your component something like this:例如,如果您选择我的其他答案中显示的方法,您可能已经在组件中声明了 TT 如下:

public TT = 
{
    // Enum defines (Horizontal | Vertical)
    FeatureBoxResponsiveLayout: FeatureBoxResponsiveLayout   
}

To show a different layout in your HTML, you'd have an *ngIf for each layout type, and you could refer directly to the enum in your component's HTML:要在 HTML 中显示不同的布局,您需要为每种布局类型设置一个*ngIf ,并且可以直接引用组件 HTML 中的枚举:

*ngIf="(featureBoxResponsiveService.layout | async) == TT.FeatureBoxResponsiveLayout.Horizontal"

This example uses a service to get the current layout, runs it through the async pipe and then compares it to our enum value.这个例子使用一个服务来获取当前布局,通过异步管道运行它,然后将它与我们的枚举值进行比较。 It's pretty verbose, convoluted and not much fun to look at.它非常冗长,令人费解,而且看起来并不有趣。 It also exposes the name of the enum, which itself may be overly verbose.它还公开了枚举的名称,它本身可能过于冗长。

Alternative, that retains type safety from the HTML替代方案,保留来自 HTML 的类型安全

Alternatively you can do the following, and declare a more readable function in your component's .ts file :或者,您可以执行以下操作,并在组件的 .ts 文件中声明一个更具可读性的函数:

*ngIf="isResponsiveLayout('Horizontal')"

Much cleaner!干净多了! But what if someone types in 'Horziontal' by mistake?但是如果有人错误地输入了'Horziontal'怎么办? The whole reason you wanted to use an enum in the HTML was to be typesafe right?您想在 HTML 中使用枚举的全部原因是类型安全,对吗?

We can still achieve that with keyof and some typescript magic.我们仍然可以使用keyof和一些打字稿魔术来实现这一点 This is the definition of the function:这是函数的定义:

isResponsiveLayout(value: keyof typeof FeatureBoxResponsiveLayout)
{
    return FeatureBoxResponsiveLayout[value] == this.featureBoxResponsiveService.layout.value;
}

Note the usage of FeatureBoxResponsiveLayout[string] which converts the string value passed in to the numeric value of the enum.请注意FeatureBoxResponsiveLayout[string]的用法, FeatureBoxResponsiveLayout[string]传入的字符串值转换为枚举的数值。

This will give an error message with an AOT compilation if you use an invalid value.如果您使用无效值,这将给出带有 AOT 编译的错误消息。

Argument of type '"H4orizontal"' is not assignable to parameter of type '"Vertical" | “H4orizo​​ntal”类型的参数不可分配给“Vertical”类型的参数 | "Horizontal" “水平的”

Currently VSCode isn't smart enough to underline H4orizontal in the HTML editor, but you'll get the warning at compile time (with --prod build or --aot switch).目前 VSCode 不够智能, H4orizontal在 HTML 编辑器中为H4orizontal加下划线,但您会在编译时收到警告(使用 --prod build 或 --aot 开关)。 This also may be improved upon in a future update.这也可能会在未来的更新中得到改进。

My component used an object myClassObject of type MyClass , which itself was using MyEnum .我的组件使用了MyClass类型的对象myClassObject ,它本身使用的是MyEnum This lead to the same issue described above.这会导致上述相同的问题。 Solved it by doing:通过执行以下操作解决了它:

export enum MyEnum {
    Option1,
    Option2,
    Option3
}
export class MyClass {
    myEnum: typeof MyEnum;
    myEnumField: MyEnum;
    someOtherField: string;
}

and then using this in the template as然后在模板中使用它作为

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

If using the 'typetable reference' approach (from @Carl G) and you're using multiple type tables you might want to consider this way :如果使用“类型表引用”方法(来自@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; 

Then access in your html file with然后在您的 html 文件中访问

{{ TT.DogType[dog] }}   => "GoldenRetriever"

I favor this approach as it makes it clear you're referring to a typetable, and also avoids unnecessary pollution of your component file.我赞成这种方法,因为它清楚地表明您指的是类型表,并且还避免了对组件文件的不必要污染。

You can also put a global TT somewhere and add enums to it as needed (if you want this you may as well make a service as shown by @VincentSels answer).您还可以在某处放置一个全局TT并根据需要向其添加枚举(如果您想要这个,您也可以创建一个服务,如@VincentSels 的回答所示)。 If you have many many typetables this may become cumbersome.如果您有很多很多类型表,这可能会变得很麻烦。

Also you always rename them in your declaration to get a shorter name.此外,您总是在声明中重命名它们以获得更短的名称。

You can now do this:你现在可以这样做:

for example, the enum is:例如,枚举是:

export enum MessagePriority {
    REGULAR= 1,
    WARNING,
    IMPORTANT,
}

a status message, that looks like this:状态消息,如下所示:

export default class StatusMessage{
    message: string;
    priority: MessagePriority;

    constructor(message: string, priority: MessagePriority){
        this.message = message;
        this.priority = priority;
    }
}

then in the .ts file of the component you can do this:然后在组件的 .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 {}
}

and finally the HTML of the component looks like this:最后组件的 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>

Notice that the enum is first declared to the class with the type of "typeof MessagePriority", then bound to the class by calling the definition with "this.messagePriority = MessagePriority"请注意,枚举首先被声明到类型为“typeof MessagePriority”的类,然后通过调用具有“this.messagePriority = MessagePriority”的定义绑定到类

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM