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

后端 未结 9 670
深忆病人
深忆病人 2020-12-07 16:13

The Typescript enum seems a natural match with Angular2\'s ngSwitch directive. But when I try to use an enum in my component\'s template, I get \"Cannot read property \'xxx

相关标签:
9条回答
  • 2020-12-07 16:39

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

    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;
      }
    }
    
    0 讨论(0)
  • 2020-12-07 16:41

    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. For instance if you choose the approach shown in my other answer, you may have declared TT in your component something like this:

    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:

    *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

    Alternatively you can do the following, and declare a more readable function in your component's .ts file :

    *ngIf="isResponsiveLayout('Horizontal')"
    

    Much cleaner! But what if someone types in 'Horziontal' by mistake? The whole reason you wanted to use an enum in the HTML was to be typesafe right?

    We can still achieve that with keyof and some typescript magic. 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.

    This will give an error message with an AOT compilation if you use an invalid value.

    Argument of type '"H4orizontal"' is not assignable to parameter of type '"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). This also may be improved upon in a future update.

    0 讨论(0)
  • 2020-12-07 16:42

    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. 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. E.g.:

    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

    <div *ngIf="someProperty === enums.MyEnumType.SomeValue">Match!</div>
    
    0 讨论(0)
  • 2020-12-07 16:43

    as of 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;
    }
    
    0 讨论(0)
  • 2020-12-07 16:45

    You can create a custom decorator to add to your component to make it aware of enums.

    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;
      }
    }
    
    0 讨论(0)
  • 2020-12-07 16:47

    This's simple and works like a charm :) just declare your enum like this and you can use it on HTML template

      statusEnum: typeof StatusEnum = StatusEnum;
    
    0 讨论(0)
提交回复
热议问题