Angular2 ngSwitch 문에서 typescript 열거 형 값을 사용하는 방법


158

Typescript 열거 형은 Angular2의 ngSwitch 지시문과 자연스럽게 일치하는 것 같습니다. 그러나 구성 요소 템플릿에서 열거 형을 사용하려고하면 "정의되지 않은 속성 'xxx'을 읽을 수 없습니다 ..."가 나타납니다. 구성 요소 템플릿에서 열거 형 값을 사용하려면 어떻게해야합니까?

이것은 열거 형 (ngFor)의 모든 값을 기반으로 html 선택 옵션을 만드는 방법과 다릅니다. 이 질문은 열거 형의 특정 값을 기반으로 한 ngSwitch에 관한 것입니다. 열거 형에 대한 클래스 내부 참조를 만드는 동일한 접근 방식이 나타납니다.



1
나는이 질문들이 중복된다고 생각하지 않는다. 다른 하나는 열거 형 (ngFor)의 모든 값을 기반으로 HTML 선택 옵션을 만드는 방법을 묻는 반면, 이것은 열거 형의 특정 값을 기반으로 한 ngSwitch입니다. 열거 형에 대한 클래스 내부 참조를 만드는 동일한 접근 방식이 나타납니다. 유사점을 지적 해 주셔서 감사합니다.
Carl G

답변:


166

구성 요소 클래스에서 열거 형에 대한 참조를 만들고 (방금 초기 문자를 소문자로 변경) 템플릿 ( 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;
  }
}

88

열거 형을 인식하도록 구성 요소에 추가 할 사용자 지정 데코레이터를 만들 수 있습니다.

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에서, 그들은 장식을 위해 가능한 사용에 누릅니다. JS의 상위 집합 인 TypeScript에는이 기능이 포함되어 있습니다.
Eric Lease

2
@Simon_Weaver이 경우 구문 설탕은에 대한 호출을 숨기고 MyEnumAware()있는데, 여기서 EnumAwareComponent인스턴스는 전달되고 속성 MyEnum이 프로토 타입에 추가됩니다. 속성 값은 열거 형 자체로 설정됩니다. 이 방법은 허용되는 답변과 동일한 기능을 수행합니다. 데코레이터에게 제안되어 TypeScript에서 허용되는 구문 설탕을 사용하고 있습니다. Angular를 사용할 때는 데코레이터 구문을 사용합니다. 그것은 Angular의 핵심 클래스가 상호 작용하는 방법을 알고있는 빈 클래스의 확장 인 a Component is 입니다.
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"합니다. 표준 숫자 열거 형을 사용하고 있습니다. AoT에서는 잘 작동하지만에서는 작동하지 않습니다 --prod. HTML에서 정수를 사용하도록 변경하면 작동하지만 요점이 아닙니다. 어떤 아이디어?
Russ

47

이것은 간단하고 매력처럼 작동합니다 :) 그냥 열거 형을 선언하면 HTML 템플릿에서 사용할 수 있습니다

  statusEnum: typeof StatusEnum = StatusEnum;

며칠간의 연구 끝에 마침내 내가 필요한 것을 발견했습니다. 많은 감사합니다!
gsiradze

@Rahul StatusEnum.ts클래스 중 하나에 정의되어 있습니다. 가져온 Angular 컴포넌트에서 컴포넌트를 컴포넌트 특성 (여기 statusEnum)에 바인드 하고 템플리트에서 컴포넌트 특성에 액세스 할 수 있습니다.
Tom

전차 대단합니다
hassan khademi

45

Angular4-HTML 템플릿에서 Enum 사용 ngSwitch / ngSwitchCase

여기에 해결책 : https://stackoverflow.com/a/42464835/802196

크레딧 : @snorkpete

귀하의 구성 요소에는

enum MyEnum{
  First,
  Second
}

그런 다음 구성 요소에서 멤버 'MyEnum'을 통해 Enum 유형을 가져오고 열거 형 변수 'myEnumVar'에 대한 다른 멤버를 만듭니다.

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

이제 .html 템플릿에서 myEnumVar 및 MyEnum을 사용할 수 있습니다. 예를 들어, 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>

다른 구성 요소에서 동일한 열거 형을 어떻게 재사용 할 수 있습니까?
ForestG

1
"export enum MyEnum {...}"을 사용하여 외부 파일에 열거를 정의해야했습니다. 그런 다음 구성 요소 파일에서 해당 외부 파일에서 'MyEnum'을 가져 와서 'MyEnum = MyEnum'등에 대한 위의 솔루션을 계속하십시오.
ObjectiveTC

16

rc.6 현재 / 최종

...

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리스의 장식에 대한 대안으로서, --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>

또한 서비스를 변경하고 @Injectable ({providedIn : 'root'})을 작성해야 작동했습니다. 감사!
Stalli

2

' 정말로 하고 싶니?'를 고려하여 시작하십시오.

HTML에서 직접 열거 형을 참조하는 데 아무런 문제가 없지만 경우에 따라 유형 안전을 잃지 않는 더 깨끗한 대안이 있습니다. 예를 들어 다른 답변에 표시된 접근 방식을 선택하면 구성 요소에서 다음과 같이 TT를 선언했을 수 있습니다.

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

HTML에 다른 레이아웃을 표시하려면 *ngIf각 레이아웃 유형마다 하나씩 있으며 구성 요소의 HTML에서 열거 형을 직접 참조 할 수 있습니다.

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

이 예제는 서비스를 사용하여 현재 레이아웃을 가져 와서 비동기 파이프를 통해 실행 한 다음 열거 형 값과 비교합니다. 꽤 장황하고 복잡하며 보는 것이별로 재미 있지 않습니다. 또한 열거 형의 이름을 공개하는데, 그 자체가 지나치게 장황 할 수 있습니다.

HTML에서 형식 안전성을 유지하는 대안

또는 다음을 수행하고 구성 요소의 .ts 파일에서 더 읽기 쉬운 함수를 선언 할 수 있습니다.

*ngIf="isResponsiveLayout('Horizontal')"

훨씬 더 깨끗합니다! 그러나 누군가 'Horziontal'실수로 입력하면 어떻게됩니까? HTML에서 열거 형을 사용하려는 모든 이유는 형식이 안전해야합니까?

우리는 여전히 keyof 와 일부 typescript 마술 로 그것을 달성 할 수 있습니다 . 이것은 함수의 정의입니다.

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

의 사용주의 FeatureBoxResponsiveLayout[string]하는 변환 열거의 숫자 값에 전달 된 문자열 값입니다.

잘못된 값을 사용하면 AOT 컴파일과 함께 오류 메시지가 표시됩니다.

""H4orizontal ""유형의 인수는 ""Vertical "유형의 매개 변수에 지정할 수 없습니다. | "수평"

현재 VSCode는 H4orizontalHTML 편집기에서 밑줄을 긋기 에는 충분하지 않지만 컴파일 타임에 --prod build 또는 --aot 스위치를 사용하여 경고를 받게됩니다. 향후 업데이트에서도 개선 될 수 있습니다.


내부 상수를 좋아하는지 확실하지 html않지만 요점을보고 사용하기 시작했습니다. 컴파일 할 때 좋은 옛날처럼 일을합니다! :)
genuinefafa

@ genuinefafa이 접근법은 실제로 열거 형 자체를 HTML에서 가져 오지만 열거 형 값을 컴파일 검사 할 수있게하는 것입니다. 나는 그것이 ts에서 html을 분리한다고 말할 수는 있지만 항상 함께 사용되기 때문에 그 자체로는 실질적인 이점을 제공하지 않는다고 가정합니다.
Simon_Weaver

I 형 체크 같은 특별히 개발 비 자동 테스트
genuinefafa

" '정말이 작업을 원하십니까?'를 고려하여 시작하십시오."
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의 'typetable reference'접근법을 사용하고 여러 유형 테이블을 사용하는 경우 다음과 같이 고려할 수 있습니다.

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 답변에 표시된 것처럼 서비스를 만들 수도 있음). 많은 typetables가 있으면 번거로울 수 있습니다.

또한 선언에서 이름을 바꾸면 이름이 짧아집니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.