ChatGPT解决这个技术问题 Extra ChatGPT

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

Typescript 枚举似乎与 Angular2 的 ngSwitch 指令自然匹配。但是当我尝试在我的组件模板中使用枚举时,我得到“无法读取...中未定义的属性'xxx'”。如何在组件模板中使用枚举值?

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

我不认为这些问题是重复的;另一个是询问如何根据枚举 (ngFor) 的所有值创建 HTML 选择选项,而这个是关于基于枚举的特定值的 ngSwitch。尽管出现了创建对枚举的类内部引用的相同方法。感谢您指出相似之处。

C
Carl G

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

h
heinob

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

  statusEnum: typeof StatusEnum = StatusEnum;

经过几天的研究终于找到了我需要的东西。非常感谢!
@Rahul StatusEnum.ts 类之一中定义。在您导入的 Angular 组件中,将其绑定到组件属性(此处为 statusEnum),并且可以从模板访问组件属性。
坦克这很棒
奇迹般有效。这将解决您在 HTML 文件中可能遇到的以下错误; “类型上不存在属性 xyz”。
有人可以举一个完整的例子吗?
E
Eric Lease

您可以创建一个自定义装饰器以添加到您的组件中,以使其了解枚举。

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

有没有人在 AoT 编译器中使用这种方法成功?
@Simon_Weaver 装饰器本质上是将函数作为参数并扩展该函数的行为的函数。对于 ES6/7,我们正在处理类的扩展/注释。这是一个high level article about how they workproposal for implementation in ES7 在 github 上 - 目前处于第 2 阶段。在该提案中,他们谈到了装饰器的可能用途。 TypeScript 是 JS 的超集,包含此功能。
@Simon_Weaver 在这种情况下,语法糖隐藏了对 MyEnumAware() 的调用,其中传递了 EnumAwareComponent 实例,并且在其原型中添加了一个属性 MyEnum。该属性的值设置为枚举本身。此方法与接受的答案相同。它只是利用了为装饰器提出并在 TypeScript 中允许的语法糖。使用 Angular 时,您立即使用装饰器语法。这就是 Component 的含义,它是 Angular 的核心类知道如何与之交互的空类的扩展。
-1:这似乎不适用于 aot,导致 ERROR in ng:///.../whatever.component.html (13,3): Property 'MyEnum' does not exist on type 'EnumAwareComponent'。这是有道理的,因为装饰器添加的属性从未被声明,打字稿编译器不知道它的存在。
所以我已经用了4个多月了。但是,现在我正在进行 --prod 构建(Ionic 3 / Angular 4 / Typescript 2.4.2)它不再有效。我收到错误 "TypeError: Cannot read property 'FirstValue' of undefined"。我正在使用标准数字枚举。它适用于 AoT,但不适用于 --prod。如果我将其更改为在 HTML 中使用整数,它确实有效,但这不是重点。有任何想法吗?
O
ObjectiveTC

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>

如何在不同的组件中重用相同的枚举?
我必须使用“export enum MyEnum {...}”在外部文件中定义枚举。然后在组件文件中,从该外部文件中导入“MyEnum”,并继续使用上面的“MyEnum = MyEnum”等解决方案。
男人,你是救命恩人!这极大地增加了可读性。对于像我这样的新手 - 不要忘记 MyEnum = MyEnum;线,没有它开关盒不起作用!
b
born2net

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

发生了什么变化?
替换为 ngSwitchCase
啊好吧。谢谢!
V
Vincent Sels

作为@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>

我还需要更改服务并编写 @Injectable({providedIn: 'root'}) 以使其工作。谢谢!
C
Community

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

我直接在 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 中的常量,但我明白你的意思并开始使用它;它在编译时完成了工作,就像过去的美好时光一样! :)
@genuinefafa 这种方法实际上是将枚举本身从 html 中取出,但仍允许对枚举值进行编译检查。我想您可以说它将 html 与 ts 分离,但这本身并没有提供任何真正的好处,因为它们总是一起使用。
我喜欢类型检查,特别是在非自动测试的开发中
因为开场白而投票赞成“首先考虑'我真的想这样做吗?'”
H
Heribert

我的组件使用了类型为 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>

S
Simon_Weaver

如果使用“类型表引用”方法(来自@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 回答所示那样提供服务)。如果你有很多很多类型表,这可能会变得很麻烦。

此外,您总是在声明中重命名它们以获得更短的名称。


I
Ivan Jamandilovski

您现在可以这样做:

例如,枚举是:

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”定义绑定到类