web-dev-qa-db-fra.com

Comment utiliser une valeur enum TypeScript dans une instruction Angular2 ngSwitch

L'énumération TypeScript semble correspondre parfaitement à la directive ngSwitch de Angular2. Mais lorsque j'essaie d'utiliser une énumération dans le modèle de mon composant, le message "Impossible de lire la propriété 'xxx' de non définie dans ...". Comment utiliser des valeurs enum dans mon modèle de composant?

Veuillez noter que ceci diffère de la façon de créer des options de sélection HTML basées sur TOUTES les valeurs d’un enum (ngFor). Cette question concerne ngSwitch basée sur une valeur particulière d'un enum. Bien que la même approche consistant à créer une référence interne à la classe enum apparaisse.

123
Carl G

Vous pouvez créer une référence à l'énum dans votre classe de composants (je viens de changer le caractère initial en minuscule), puis utiliser cette référence à partir du modèle ( 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;
  }
}
145
Carl G

Vous pouvez créer un décorateur personnalisé à ajouter à votre composant pour le rendre conscient des énumérations.

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;
  }
}
84
Eric Lease

Angular4 - Utiliser Enum dans un modèle HTML ngSwitch/ngSwitchCase

Solution ici: https://stackoverflow.com/a/42464835/802196

crédit: @snorkpete

Dans votre composant, vous avez

enum MyEnum{
  First,
  Second
}

Ensuite, dans votre composant, vous introduisez le type Enum via un membre 'MyEnum' et créez un autre membre pour votre variable enum 'myEnumVar':

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

Vous pouvez maintenant utiliser myEnumVar et MyEnum dans votre modèle .html. Par exemple, utiliser Enums dans 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>
34
ObjectiveTC

C'est simple et fonctionne comme un charme :) déclarez simplement votre enum comme ceci et vous pourrez l'utiliser sur un template HTML

  statusEnum: typeof SatusEnum = SatusEnum;
24
Aymen Boumaiza

à partir de 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;
}
15
born2net

Comme alternative au décorateur de @Eric Lease, qui ne fonctionne malheureusement pas avec les constructions --aot (et donc --prod), j'ai eu recours à un service exposant tous les enum de mon application. Il suffit d’injecter publiquement cela dans chaque composant qui le nécessite, sous un nom simple, après quoi vous pouvez accéder aux enums de vos vues. Par exemple.:

Service

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

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

N'oubliez pas de l'inclure dans la liste des fournisseurs de votre module.

classe de composant

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

  // ...
}

Composant html

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

Commencez par considérer "Est-ce que je veux vraiment faire cela?

Je n'ai aucun problème à faire référence à des énumérations directement en HTML, mais dans certains cas, il existe des alternatives plus propres qui ne perdent pas la sécurité de type. Par exemple, si vous choisissez l'approche indiquée dans mon autre réponse, vous avez peut-être déclaré TT dans votre composant, par exemple:

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

Pour afficher une présentation différente dans votre code HTML, vous devez utiliser un *ngIf pour chaque type de disposition, et vous pouvez vous référer directement à l'énum dans le code HTML de votre composant:

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

Cet exemple utilise un service pour obtenir la mise en page actuelle, l'exécute via le canal asynchrone puis la compare à notre valeur enum. C'est assez verbeux, compliqué et pas très amusant à regarder. Il expose également le nom de l'énum, ​​qui peut être trop verbeux.

Alternative, qui conserve la sécurité de type du HTML

Vous pouvez également effectuer les opérations suivantes et déclarer une fonction plus lisible dans le fichier .ts de votre composant:

*ngIf="isResponsiveLayout('Horizontal')"

Beaucoup plus propre! Mais que se passe-t-il si quelqu'un tape 'Horziontal' par erreur? La seule raison pour laquelle vous vouliez utiliser une énumération dans le code HTML était d’être dactylographiée?

Nous pouvons toujours y parvenir avec keyof et un peu de magie TypeScript. Voici la définition de la fonction:

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

Notez l'utilisation de FeatureBoxResponsiveLayout[string] qui convertit la valeur de chaîne transmise à la valeur numérique de l'énum.

Cela donnera un message d'erreur avec une compilation AOT si vous utilisez une valeur invalide.

L'argument de type '"H4orizontal"' n'est pas assignable au paramètre de type '"Vertical" | "Horizontal"

Actuellement, VSCode n'est pas assez intelligent pour souligner H4orizontal dans l'éditeur HTML, mais vous obtenez l'avertissement au moment de la compilation (avec --prod build ou --aot switch). Cela peut également être amélioré dans une future mise à jour.

2
Simon_Weaver

Si vous utilisez l'approche "référence typetable" (de @Carl G) et que vous utilisez plusieurs tables de types, vous pouvez envisager cette méthode:

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; 

Accédez ensuite à votre fichier html avec

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

Je suis favorable à cette approche car elle indique clairement que vous faites référence à une table de saisie et évite également une pollution inutile de votre fichier de composant.

Vous pouvez également placer un TT global quelque part et y ajouter une énumération si nécessaire (si vous le souhaitez, vous pouvez également créer un service comme indiqué par la réponse @VincentSels). Si vous avez beaucoup de tables de types, cela peut devenir fastidieux.

En outre, vous les renommez toujours dans votre déclaration pour obtenir un nom plus court.

1
Simon_Weaver

Mon composant utilisait un objet myClassObject de type MyClass, qui utilisait lui-même MyEnum. Cela a conduit au même problème décrit ci-dessus. Résolu en faisant:

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

puis en utilisant cela dans le modèle comme

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