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.
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;
}
}
Vous pouvez créer un décorateur personnalisé à ajouter à votre composant pour le rendre conscient des énumérations.
export enum MyEnum {
FirstValue,
SecondValue
}
import { MyEnum } from './myenum.enum';
export function MyEnumAware(constructor: Function) {
constructor.prototype.MyEnum = MyEnum;
}
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;
}
}
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>
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;
à 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;
}
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>
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.
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.
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.
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>