วิธีใช้ค่า typescript enum ในคำสั่ง Angular2 ngSwitch


158

typescript enum ดูเหมือนว่าจะเป็นไปตามธรรมชาติกับคำสั่ง ngSwitch ของ Angular2 แต่เมื่อฉันพยายามใช้ enum ในแม่แบบขององค์ประกอบฉันได้รับ "ไม่สามารถอ่านคุณสมบัติ 'xxx' ของไม่ได้กำหนดใน ... " ฉันจะใช้ค่า enum ในแม่แบบองค์ประกอบของฉันได้อย่างไร

โปรดทราบว่าสิ่งนี้แตกต่างจากวิธีการสร้างตัวเลือกการเลือก html ตามค่าทั้งหมดของ enum (ngFor) คำถามนี้เกี่ยวกับ ngSwitch ตามค่าเฉพาะของ enum แม้ว่าวิธีการเดียวกันในการสร้างการอ้างอิงภายในคลาสถึง enum จะปรากฏขึ้น


สำเนาซ้ำที่เป็นไปได้ของSelect ตาม enum ใน Angular2
GünterZöchbauer

1
ฉันไม่คิดว่าคำถามเหล่านี้ซ้ำซ้อน; อีกคนหนึ่งถามถึงวิธีการสร้างตัวเลือก HTML ที่เลือกตามค่าทั้งหมดของ enum (ngFor) ในขณะที่อันนี้เป็นเรื่องเกี่ยวกับ ngSwitch ตามค่าเฉพาะของ enum แม้ว่าวิธีการเดียวกันในการสร้างการอ้างอิงภายในคลาสถึง enum จะปรากฏขึ้น ขอบคุณสำหรับการชี้ให้เห็นความคล้ายคลึงกัน
Carl G

คำตอบ:


166

คุณสามารถสร้างการอ้างอิงไปยัง enum ในคลาสคอมโพเนนต์ของคุณ (ฉันเพิ่งเปลี่ยนอักขระเริ่มต้นเป็นตัวพิมพ์เล็ก) จากนั้นใช้การอ้างอิงนั้นจากเทมเพลต ( พลั่วเกอร์ ):

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

88

คุณสามารถสร้างมัณฑนากรที่กำหนดเองเพื่อเพิ่มองค์ประกอบของคุณเพื่อให้ตระหนักถึง 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;
  }
}

7
มีใครประสบความสำเร็จในการใช้วิธีการนี้กับคอมไพเลอร์ AoT หรือไม่?
Danny

2
@Simon_Weaver มัณฑนากรเป็นฟังก์ชันหลักที่ใช้ฟังก์ชั่นเป็นพารามิเตอร์และขยายพฤติกรรมของฟังก์ชั่นนั้น ในกรณีของ ES6 / 7 เรากำลังจัดการกับส่วนขยาย / หมายเหตุประกอบของชั้นเรียน นี่คือบทความระดับสูงเกี่ยวกับวิธีการทำงานบทความระดับสูงเกี่ยวกับวิธีที่พวกเขาทำงานข้อเสนอสำหรับการดำเนินงานใน ES7อยู่บน GitHub - ขณะนี้อยู่ในขั้นตอนที่ 2 ในเรื่องที่พวกเขาสัมผัสกับการใช้งานที่เป็นไปได้สำหรับตกแต่ง TypeScript ซึ่งเป็นส่วนเสริมของ JS รวมถึงฟีเจอร์นี้
Eric Lease

2
@Simon_Weaver ในกรณีนี้น้ำตาล syntactic ซ่อนการโทรไปMyEnumAware()ที่ซึ่งEnumAwareComponentอินสแตนซ์ถูกส่งผ่านและมีคุณสมบัติMyEnumเพิ่มไปยังต้นแบบ ค่าของคุณสมบัติถูกตั้งค่า enum เอง วิธีนี้ทำในสิ่งเดียวกันกับคำตอบที่ยอมรับ เป็นเพียงการใช้ประโยชน์จากน้ำตาลทรายที่เสนอสำหรับผู้ตกแต่งและอนุญาตใน TypeScript เมื่อใช้ Angular คุณกำลังใช้ไวยากรณ์ของมัณฑนากรทันที นั่นคือสิ่งที่Component เป็นส่วนขยายของชั้นว่างที่ชั้นเรียนหลักของ Angular รู้วิธีการโต้ตอบกับ
Eric Lease

5
-1: สิ่งนี้ดูเหมือนจะไม่ทำงานกับ aot ส่งผลให้ ERROR in ng:///.../whatever.component.html (13,3): Property 'MyEnum' does not exist on type 'EnumAwareComponent'นี้จะไม่ปรากฏในการทำงานกับทอทผลใน สิ่งนี้สมเหตุสมผลเนื่องจากคุณสมบัติที่มัณฑนากรเพิ่มนั้นไม่เคยถูกประกาศออกไปทำให้คอมไพเลอร์ตัวพิมพ์ไม่ทราบว่ามีอยู่จริง
meriton

2
ดังนั้นฉันใช้สิ่งนี้มา 4 เดือนแล้ว อย่างไรก็ตามตอนนี้ฉันกำลัง--prodสร้าง (Ionic 3 / Angular 4 / Typescript 2.4.2) มันไม่ทำงานอีกต่อไป "TypeError: Cannot read property 'FirstValue' of undefined"ฉันได้รับข้อผิดพลาด ฉันใช้ตัวเลข enum มาตรฐาน มันทำงานได้ดีกับมหาชน --prodแต่ไม่ได้มี มันใช้งานได้ถ้าฉันเปลี่ยนเป็นการใช้จำนวนเต็มใน HTML แต่นั่นไม่ใช่ประเด็น ความคิดใด ๆ
รัส

47

สิ่งนี้ง่ายและใช้งานได้อย่างมีเสน่ห์ :) เพียงประกาศ enum ของคุณแบบนี้และคุณสามารถใช้มันในเทมเพลต HTML

  statusEnum: typeof StatusEnum = StatusEnum;

หลังจากวันของการวิจัยในที่สุดก็พบสิ่งที่ฉันต้องการ ขอบคุณมาก!
gsiradze

@Rahul StatusEnumถูกกำหนดใน.tsคลาสใดคลาสหนึ่ง ในองค์ประกอบ Angular ที่คุณนำเข้าให้ผูกเข้ากับคุณสมบัติของส่วนประกอบ (ที่นี่statusEnum) และคุณสมบัติของส่วนประกอบสามารถเข้าถึงได้จากเทมเพลต
ทอม

รถถังนี้เยี่ยมมาก
hassan khademi

45

Angular4 - การใช้ Enum ในเทมเพลต HTML ngSwitch / ngSwitchCase

ทางออกที่นี่: https://stackoverflow.com/a/42464835/802196

เครดิต: @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>

วิธีที่คุณสามารถใช้ซ้ำ enum เดียวกันในองค์ประกอบที่แตกต่างกันได้อย่างไร
ForestG

1
ฉันต้องกำหนด enum ในไฟล์ภายนอกโดยใช้ "export enum MyEnum {... }" จากนั้นในไฟล์คอมโพเนนต์ให้นำเข้า 'MyEnum' จากไฟล์ภายนอกนั้นและดำเนินการตามวิธีแก้ปัญหาข้างต้นสำหรับ 'MyEnum = MyEnum "ฯลฯ
ObjectiveTC

16

ตั้งแต่ 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;
}

1
มีการเปลี่ยนแปลงอย่างไร
Carl G

แทนที่ด้วย ngSwitchCase
born2net

อ่าโอเค. ขอบคุณ!
Carl G

14

เป็นทางเลือกของมัณฑนากรของ @Eric Lease ซึ่งน่าเสียดายที่ไม่สามารถใช้งานได้ --aot (และเช่นนั้น--prod) ฉันได้ใช้บริการที่ทำให้แอปพลิเคชันทั้งหมดของฉันปรากฏ เพียงแค่ต้องทำการแทรกสิ่งนั้นลงในแต่ละองค์ประกอบที่ต้องใช้ภายใต้ชื่อง่าย ๆ หลังจากนั้นคุณสามารถเข้าถึง enums ในมุมมองของคุณ เช่น:

บริการ

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>

ฉันต้องเปลี่ยนบริการและเขียน @Injectable ({ที่ระบุไว้: 'รูท'}) เพื่อให้มันทำงานได้ ขอบคุณ!
Stalli

2

เริ่มต้นด้วยการพิจารณา 'ฉันจริง ๆต้องการที่จะทำเช่นนี้?'

ฉันไม่มีปัญหาในการอ้างถึง enums โดยตรงใน HTML แต่ในบางกรณีมีทางเลือกที่สะอาดกว่าที่ไม่สูญเสียความปลอดภัยประเภท ตัวอย่างเช่นหากคุณเลือกวิธีที่แสดงในคำตอบอื่น ๆ ของฉันคุณอาจประกาศ TT ในองค์ประกอบของคุณดังนี้:

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

ในการแสดงเลย์เอาต์ที่แตกต่างใน HTML ของคุณคุณจะต้องมี*ngIfเลย์เอาต์แต่ละประเภทและคุณสามารถอ้างอิงโดยตรงกับ enum ใน HTML ของส่วนประกอบของคุณ:

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

ตัวอย่างนี้ใช้บริการเพื่อรับเค้าโครงปัจจุบันเรียกใช้ผ่านท่อ async แล้วเปรียบเทียบกับค่า enum ของเรา เป็นเรื่องที่ค่อนข้างละเอียดซับซ้อนและไม่ค่อยสนุกที่จะดู นอกจากนี้ยังเปิดเผยชื่อของ enum ซึ่งตัวเองอาจจะ verbose มากเกินไป

อีกทางเลือกหนึ่งที่รักษาความปลอดภัยประเภทจาก HTML

หรือคุณสามารถทำสิ่งต่อไปนี้และประกาศฟังก์ชั่นที่อ่านได้มากขึ้นในไฟล์. ts ของส่วนประกอบ:

*ngIf="isResponsiveLayout('Horizontal')"

ทำความสะอาดมาก! แต่ถ้ามีคนพิมพ์'Horziontal'ผิดพลาดล่ะ? เหตุผลทั้งหมดที่คุณต้องการใช้ enum ใน HTML นั้นเพื่อความปลอดภัย

เรายังคงสามารถบรรลุได้ด้วยkeyofและเวทมนต์บทกลอนบางส่วน นี่คือนิยามของฟังก์ชัน:

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

สังเกตการใช้งานFeatureBoxResponsiveLayout[string]ที่แปลงค่าสตริงที่ส่งผ่านไปเป็นค่าตัวเลขของ enum

สิ่งนี้จะให้ข้อความแสดงข้อผิดพลาดพร้อมการรวบรวม AOT หากคุณใช้ค่าที่ไม่ถูกต้อง

อาร์กิวเมนต์ประเภท '"H4 แนวนอน"' ไม่สามารถกำหนดให้กับพารามิเตอร์ประเภท "" แนวตั้ง "| "แนวนอน"

ปัจจุบัน VSCode ยังไม่ฉลาดพอที่จะขีดเส้นใต้H4orizontalในตัวแก้ไข HTML แต่คุณจะได้รับคำเตือนในเวลารวบรวม (ด้วย --prod build หรือ --aot switch) สิ่งนี้อาจได้รับการปรับปรุงในการปรับปรุงในอนาคต


ไม่แน่ใจว่าฉันชอบค่าคงที่ข้างในหรือไม่htmlแต่ฉันเห็นประเด็นของคุณและเริ่มใช้มัน มันทำงานได้ดีเหมือนสมัยก่อนเมื่อรวบรวม! :)
authenticfafa

@genuinefafa วิธีการนี้เป็นเรื่องเกี่ยวกับการเอา enum ออกจาก html แต่ยังอนุญาตให้มีการตรวจสอบค่า enum ฉันคิดว่าคุณสามารถพูดได้ว่ามันถอดรหัส html จาก ts แต่ในตัวมันเองนั้นไม่ได้ให้ประโยชน์ใด ๆ เลยเพราะมันถูกใช้ร่วมกันเสมอ
Simon_Weaver

ฉันชอบการตรวจสอบประเภทโดยเฉพาะในการพัฒนาที่ไม่ผ่านการทดสอบโดยอัตโนมัติ
authenticfafa

upvote เนื่องจากการเปิดบรรทัด "เริ่มต้นด้วยการพิจารณา 'ฉันต้องการทำสิ่งนี้จริงๆหรือไม่?'"
WebDever

2

ส่วนประกอบของฉันใช้วัตถุ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>

1

หากใช้วิธีการอ้างอิงที่พิมพ์ได้ (จาก @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"

ฉันชอบวิธีนี้เพราะเห็นได้ชัดว่าคุณอ้างถึง typetable และหลีกเลี่ยงมลภาวะที่ไม่จำเป็นของไฟล์ส่วนประกอบของคุณ

นอกจากนี้คุณยังสามารถใส่ทั่วโลกTTและเพิ่มจำนวนได้ตามต้องการ (ถ้าคุณต้องการสิ่งนี้คุณก็สามารถให้บริการตามที่แสดงโดย @VincentSels answer) หากคุณมีงานพิมพ์มากมายหลายอย่างสิ่งนี้อาจยุ่งยาก

นอกจากนี้คุณมักจะเปลี่ยนชื่อพวกเขาในการประกาศของคุณเพื่อให้ได้ชื่อที่สั้นลง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.