Подтвердить что ты не робот

Как использовать значение enum typescript в выражении Angular2 ngSwitch

Переменная Typescript представляется естественным совпадением с директивой Angular2 ngSwitch. Но когда я пытаюсь использовать перечисление в моем шаблоне компонента, я получаю "Не могу прочитать свойство" xxx "из undefined in...". Как я могу использовать значения перечисления в моем шаблоне компонента?

Обратите внимание, что это отличается от того, как создавать параметры выбора html на основе ВСЕХ значений enum (ngFor). Этот вопрос касается ngSwitch, основанного на конкретном значении перечисления. Хотя появляется тот же подход создания внутренней ссылки на enum для класса.

4b9b3361

Ответ 1

Вы можете создать ссылку на перечисление в своем классе компонента (я просто изменил начальный символ на нижний регистр), а затем используйте эту ссылку из шаблона (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;
  }
}

Ответ 2

Вы можете создать пользовательский декоратор, который будет добавлен в ваш компонент, чтобы он знал о перечислениях.

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

Ответ 3

Angular4 - Использование Enum в HTML-шаблоне ngSwitch/ngSwitchCase

Решение здесь: fooobar.com/questions/94874/...

кредит: @snorkpete

В вашем компоненте у вас есть

enum MyEnum{
  First,
  Second
}

Затем в вашем компоненте вы вводите тип Enum через член 'MyEnum' и создаете другой член для переменной enum 'myEnumVar':

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

Теперь вы можете использовать myEnumVar и MyEnum в своем шаблоне .html. Например, с помощью Enums в 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>

Ответ 4

Это просто и работает как шарм :) просто объявите свой enum вот так, и вы можете использовать его в шаблоне HTML

  statusEnum: typeof SatusEnum = SatusEnum;

Ответ 5

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

Ответ 6

В качестве альтернативы @Eric Lease decorator, который, к сожалению, не работает с использованием --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>

Ответ 7

Начните с размышления "Действительно ли я хочу это сделать?"

У меня нет проблем со ссылками на перечисления непосредственно в HTML, но в некоторых случаях есть более чистые альтернативы, которые не теряют безопасность типов. Например, если вы выберете подход, показанный в моем другом ответе, возможно, вы объявили TT в своем компоненте примерно так:

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

Чтобы показать другой макет в вашем HTML, у вас должен быть *ngIf для каждого типа макета, и вы можете напрямую обратиться к enum в вашем компоненте HTML:

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

В этом примере используется служба для получения текущей компоновки, она запускается через асинхронный канал и затем сравнивается с нашим значением перечисления. Это довольно многословно, запутанно и не очень интересно смотреть. Это также выставляет имя enum, которое само по себе может быть слишком многословным.

Альтернатива, которая сохраняет безопасность типов из HTML

В качестве альтернативы вы можете сделать следующее и объявить более читабельную функцию в вашем файле компонента .ts:

*ngIf="isResponsiveLayout('Horizontal')"

Гораздо чище! Но что, если кто 'Horziontal' по ошибке? Вся причина, по которой вы хотели использовать enum в HTML, была в том, чтобы быть безопасным, не так ли?

Мы все еще можем достичь этого с помощью keyof и некоторой магии машинописи. Это определение функции:

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

Обратите внимание на использование FeatureBoxResponsiveLayout[string] который преобразует переданное строковое значение в числовое значение перечисления.

Это даст сообщение об ошибке с компиляцией AOT, если вы используете недопустимое значение.

Аргумент типа "H4orizontal" не может быть присвоен параметру типа "Vertical" | "Горизонтальный"

В настоящее время VSCode не достаточно умен, чтобы подчеркнуть H4orizontal в редакторе HTML, но вы получите предупреждение во время компиляции (с помощью --prod build или --aot switch). Это также может быть улучшено в будущем обновлении.

Ответ 8

Если вы используете подход 'typetable reference' (из @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). Если у вас много разных таблиц, это может стать громоздким.

Также вы всегда переименовываете их в своем объявлении, чтобы получить более короткое имя.

Ответ 9

Мой компонент использовал объект 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>