如何在Angular2 ngSwitch语句

时间:2016-03-07 04:02:02

标签: typescript angular

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

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

9 个答案:

答案 0 :(得分:138)

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

答案 1 :(得分:83)

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

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

答案 2 :(得分:32)

Angular4 - 在HTML模板中使用枚举ngSwitch / ngSwitchCase

此处的解决方案:https://stackoverflow.com/a/42464835/802196

信用:@snorkpete

在您的组件中,您有

enum MyEnum{
  First,
  Second
}

然后在您的组件中,您通过会员&#39; MyEnum&#39;引入Enum类型,并为您的枚举变量&#39; myEnumVar&#39;创建另一个成员。 :

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>

答案 3 :(得分:15)

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

  statusEnum: typeof SatusEnum = SatusEnum;

答案 4 :(得分:14)

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

答案 5 :(得分:6)

作为@Eric Lease的装饰器的一种替代方法,不幸的是,该装饰器无法使用namespace AdMobTestProject { public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); } } public class AdMobView : ContentView { public AdMobView() { } } } (因此,<div id="register-modal" class="modal fade" tabindex="-1" role="dialog" aria- hidden="true"> <div class="modal-dialog modal-lg" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" aria-label="Close" (click)="closeModal()"> <span aria-hidden="true">&times;</span> </button> <h4 class="modal-title" style="text-align:center">Register</h4> </div> <form name="registerForm" #registerForm="ngForm" (ngSubmit)=" !errordata.isErrorData && registerForm.valid && registerManager()"> <div class="modal-body"> <div class="container-fluid"> <div class="row"> <div class="col-md-12"> <div class="box"> <div class="box-body"> <div class="box box-solid box-primary"> <div class="row"> <div class="col-md-6"> <div class="form-group"> <label class="col-sm-3 control-label">First Name <span style="color:red">*</span> </label> <div class="col-sm-9"> <input type="text" placeholder="First Name" [(ngModel)]="registerData.firstName" name="firstName" class="form-control" pattern="[a-zA-Z/s ]*" maxlength="20" #firstName="ngModel" required> <div *ngIf="firstName.valid || firstName.touched || registerForm.submitted"> <div class="error-msg" *ngIf="firstName.errors && firstName.errors.required" class="text-danger"> First Name is required. </div> <div class="error-msg" *ngIf="firstName.errors && firstName.errors.pattern" class="text-danger"> Enter Valid First Name. </div> </div> </div> </div> </div> <div class="col-md-6"> <div class="form-group"> <label class="col-sm-3 control-label">Last Name <span style="color:red">*</span> </label> <div class="col-sm-9"> <input type="text" placeholder="Last Name" [(ngModel)]="registerData.lastName" name="lastName" class="form-control" pattern="[a-zA-Z/s ]*" maxlength="20" #lastName="ngModel" required> <div *ngIf="lastName.valid || lastName.touched || registerForm.submitted"> <div class="error-msg" *ngIf="lastName.errors && lastName.errors.required" class="text-danger"> Last Name is required. </div> <div class="error-msg" *ngIf="lastName.errors && lastName.errors.pattern" class="text-danger"> Enter Valid Name. </div> </div> </div> </div> </div> </div> <br> <div class="row"> <div class="col-md-6"> <div class="form-group"> <label class="col-sm-3 control-label">Email <span style="color:red">*</span> </label> <div class="col-sm-9"> <input type="email" placeholder="Email" [(ngModel)]="registerData.email" name="email" class="form-control" #email="ngModel" (blur)="checkEmail(registerData.email)" required pattern="[_a-z0-9]+(\.[_a-z0-9]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})"> <div *ngIf="email.valid || email.touched || registerForm.submitted"> <div class="error-msg" *ngIf="email.errors && email.errors.required" class="text-danger"> Email is required. </div> <div class="error-msg" *ngIf="email.errors && email.errors.pattern" class="text-danger"> Enter Valid Eamil. </div> <div *ngIf="errordata.isErrorData" class="text-danger"> {{ errordata.errorMessage }}</div> </div> </div> </div> </div> <div class="col-md-6"> <div class="form-group"> <label class="col-sm-3 control-label">Password <span style="color:red">*</span> </label> <div class="col-sm-9"> <input type="password" placeholder="Password" [(ngModel)]="registerData.password" name="password" class="form-control" maxlength="20" #password="ngModel" required> <div *ngIf="password.valid || password.touched || registerForm.submitted"> <div class="error-msg" *ngIf="password.errors && password.errors.required" class="text-danger"> Password is required. </div> <div class="error-msg" *ngIf="password.errors && password.errors.pattern" class="text-danger"> Enter Valid Password. </div> </div> </div> </div> </div> </div> <br> <div class="row"> <div class="col-md-6"> <div class="form-group"> <label class="col-sm-3 control-label">Date Of Birth <span style="color:red">*</span> </label> <div class="col-sm-9"> <input type="date" placeholder="DOB" [(ngModel)]="registerData.dateOfBirth" name="dob" class="form-control" #dob="ngModel" required> <div *ngIf="dob.valid || dob.touched || registerForm.submitted"> <div class="error-msg" *ngIf="dob.errors && dob.errors.required" class="text-danger"> dob is required. </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> <div class="modal-footer"> <div class="pull-right"> <button type="submit" class="btn btn-primary">Submit</button> </div> <div class="pull-left"> <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> </div> </div> </form> </div> </div> </div> )构建无法工作,我求助于使用公开我所有应用程序枚举的服务。只需以简单的名称将其公开地注入到需要它的每个组件中,之后您就可以访问视图中的枚举了。例如:

服务

--aot

请不要忘记将其包括在模块的提供者列表中。

组件类

--prod

组件html

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

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

答案 6 :(得分:2)

首先考虑“我真的要这么做吗?”

我在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和一些打字稿魔术来实现这一目标。这是函数的定义:

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

请注意FeatureBoxResponsiveLayout[string]的用法,其中converts字符串值传递给枚举的数值。

如果您使用无效的值,这将给出一条错误消息,提示AOT编译。

  

不能将类型“ H4orizo​​ntal”的参数分配给类型“垂直”的参数。 “水平”

当前,VSCode不够智能,无法在HTML编辑器中对H4orizontal下划线,但是您会在编译时收到警告(使用--prod build或--aot开关)。将来的更新中可能还会对此进行改进。

答案 7 :(得分:1)

如果使用&#39; typetable参考&#39;方法(来自@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答案显示服务)。如果你有很多类型表,这可能会变得很麻烦。

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

答案 8 :(得分:0)

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