Cách sử dụng giá trị enum bản in trong câu lệnh Angular2 ngSwitch


158

Enum typecript có vẻ phù hợp tự nhiên với chỉ thị ngSwitch của Angular2. Nhưng khi tôi cố gắng sử dụng một enum trong mẫu của thành phần, tôi nhận được "Không thể đọc thuộc tính 'xxx' không xác định trong ...". Làm cách nào để sử dụng giá trị enum trong mẫu thành phần của tôi?

Xin lưu ý rằng điều này khác với cách tạo tùy chọn chọn html dựa trên TẤT CẢ các giá trị của một enum (ngFor). Câu hỏi này là về ngSwitch dựa trên một giá trị cụ thể của một enum. Mặc dù cách tiếp cận tương tự của việc tạo một tham chiếu nội bộ lớp cho enum xuất hiện.



1
Tôi không nghĩ rằng những câu hỏi này là trùng lặp; một cái khác đang hỏi làm thế nào để tạo các tùy chọn HTML dựa trên TẤT CẢ các giá trị của một enum (ngFor), trong khi cái này là về ngSwitch dựa trên một giá trị cụ thể của enum. Mặc dù cách tiếp cận tương tự của việc tạo một tham chiếu nội bộ lớp cho enum xuất hiện. Cảm ơn bạn đã chỉ ra sự tương đồng.
Carl G

Câu trả lời:


166

Bạn có thể tạo một tham chiếu đến enum trong lớp thành phần của mình (tôi chỉ thay đổi ký tự ban đầu thành chữ thường) và sau đó sử dụng tham chiếu đó từ mẫu ( 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

Bạn có thể tạo một trang trí tùy chỉnh để thêm vào thành phần của bạn để làm cho nó nhận biết về enums.

myenum.enum.ts:

export enum MyEnum {
    FirstValue,
    SecondValue
}

myenumwar.decorator.ts

import { MyEnum } from './myenum.enum';

export function MyEnumAware(constructor: Function) {
    constructor.prototype.MyEnum = MyEnum;
}

enum-nhận thức.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
Có ai đã thành công khi sử dụng phương pháp này với trình biên dịch AoT chưa?
Daniel

2
Trình trang trí @Simon_Weaver về cơ bản là các hàm lấy một hàm làm tham số và mở rộng hành vi của hàm đó. Trong trường hợp ES6 / 7, chúng tôi đang xử lý việc mở rộng / chú thích các lớp. Đây là một bài viết cấp cao về cách họ làm việc . Các đề nghị cho thực hiện trong ES7 là trên github - hiện đang ở giai đoạn 2. Trong đề nghị đó, họ chạm vào sử dụng có thể cho trang trí. TypeScript, là một superset của JS, bao gồm tính năng này.
Eric thuê

2
@Simon_Weaver Trong trường hợp này, đường cú pháp đang ẩn cuộc gọi đến MyEnumAware(), nơi EnumAwareComponentcá thể được thông qua và có một thuộc tính MyEnum, được thêm vào nguyên mẫu của nó. Giá trị của tài sản được đặt enum chính nó. Phương pháp này thực hiện tương tự như câu trả lời được chấp nhận. Đó chỉ là lợi dụng đường cú pháp được đề xuất cho các nhà trang trí và được phép trong TypeScript. Khi sử dụng Angular, bạn đang sử dụng cú pháp trang trí ngay lập tức. Đó là những gì một Component , một phần mở rộng của một lớp trống lớp lõi kiễu góc của biết làm thế nào để tương tác với.
Eric thuê

5
-1: Điều này dường như không hoạt động với aot, dẫn đến ERROR in ng:///.../whatever.component.html (13,3): Property 'MyEnum' does not exist on type 'EnumAwareComponent'. Điều này có ý nghĩa, bởi vì thuộc tính mà trình trang trí thêm vào không bao giờ được khai báo, khiến trình biên dịch bản thảo không biết đến sự tồn tại của nó.
meriton

2
Vì vậy, tôi đã sử dụng điều này trong hơn 4 tháng. Tuy nhiên, bây giờ khi tôi đang --prodxây dựng (Ionic 3 / Angular 4 / Typecript 2.4.2) thì nó không còn hoạt động nữa. Tôi nhận được lỗi "TypeError: Cannot read property 'FirstValue' of undefined". Tôi đang sử dụng một enum số tiêu chuẩn. Nó hoạt động tốt với AoT nhưng không phải với --prod. Nó hoạt động nếu tôi thay đổi nó thành sử dụng số nguyên trong HTML, nhưng đó không phải là vấn đề. Có ý kiến ​​gì không?
Nga

47

Điều này đơn giản và hoạt động như một bùa mê :) chỉ cần khai báo enum của bạn như thế này và bạn có thể sử dụng nó trên mẫu HTML

  statusEnum: typeof StatusEnum = StatusEnum;

Sau những ngày nghiên cứu cuối cùng đã tìm thấy những gì tôi cần. Cảm ơn nhiều!
gsiradze

@Rahul StatusEnumđược định nghĩa trong một trong các .tslớp. Trong thành phần Angular bạn nhập nó, liên kết nó với một thuộc tính thành phần (ở đây statusEnum) và các thuộc tính thành phần có thể truy cập được từ mẫu.
tom

xe tăng này thật tuyệt
HSN KH

45

Angular4 - Sử dụng Enum trong Mẫu HTML ngSwitch / ngSwitchCase

Giải pháp tại đây: https://stackoverflow.com/a/42464835/802196

tín dụng: @snorkpete

Trong thành phần của bạn, bạn có

enum MyEnum{
  First,
  Second
}

Sau đó, trong thành phần của bạn, bạn mang loại Enum thông qua một thành viên 'MyEnum' và tạo một thành viên khác cho biến enum của bạn 'myEnumVar':

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

Bây giờ bạn có thể sử dụng myEnumVar và MyEnum trong mẫu .html của bạn. Ví dụ: Sử dụng Enums trong 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>

Làm thế nào bạn có thể tái sử dụng cùng một enum trong một thành phần khác nhau?
ForestG

1
Tôi đã phải xác định enum trong một tệp bên ngoài bằng cách sử dụng "export enum MyEnum {...}". Sau đó, trong tệp thành phần, nhập 'MyEnum' từ tệp bên ngoài đó và tiếp tục với giải pháp ở trên cho 'MyEnum = MyEnum ", v.v.
ObjectiveTC

16

kể từ RC.6 / trận chung kết

...

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
Điều gì đã thay đổi?
Carl G

được thay thế bằng ngSwitchCase
sinh2net

À được rồi. Cảm ơn!
Carl G

14

Thay thế cho công cụ trang trí của @Eric Hire, không may sử dụng các bản dựng --aot(và do đó --prod), tôi đã sử dụng một dịch vụ làm lộ tất cả các ứng dụng của ứng dụng của tôi. Chỉ cần công khai tiêm nó vào từng thành phần yêu cầu nó, dưới một tên dễ dàng, sau đó bạn có thể truy cập các enum trong chế độ xem của mình. Ví dụ:

Dịch vụ

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

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

Đừng quên đưa nó vào danh sách nhà cung cấp mô-đun của bạn.

Lớp thành phần

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

  // ...
}

Thành phần html

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

Tôi cũng cần thay đổi dịch vụ và viết @Injectable ({cung cấp: 'root'}) để làm cho nó hoạt động. Cảm ơn!
Stalli

2

Bắt đầu bằng cách xem xét 'Tôi có thực sự muốn làm điều này không?'

Tôi không có vấn đề gì khi đề cập đến enum trực tiếp trong HTML, nhưng trong một số trường hợp, có những lựa chọn thay thế sạch hơn mà không mất tính an toàn kiểu. Chẳng hạn, nếu bạn chọn cách tiếp cận được hiển thị trong câu trả lời khác của tôi, bạn có thể đã khai báo TT trong thành phần của mình giống như thế này:

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

Để hiển thị bố cục khác nhau trong HTML của bạn, bạn có một *ngIfloại bố cục và bạn có thể tham khảo trực tiếp đến enum trong HTML của thành phần:

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

Ví dụ này sử dụng một dịch vụ để có được bố cục hiện tại, chạy nó qua ống async và sau đó so sánh nó với giá trị enum của chúng tôi. Nó khá dài dòng, phức tạp và không có nhiều niềm vui để xem xét. Nó cũng tiết lộ tên của enum, mà bản thân nó có thể quá dài dòng.

Thay thế, vẫn giữ an toàn loại từ HTML

Ngoài ra, bạn có thể thực hiện các thao tác sau và khai báo một hàm dễ đọc hơn trong tệp .ts của thành phần:

*ngIf="isResponsiveLayout('Horizontal')"

Sạch sẽ hơn nhiều! Nhưng nếu ai đó gõ 'Horziontal'nhầm thì sao? Toàn bộ lý do bạn muốn sử dụng một enum trong HTML là để an toàn đúng không?

Chúng ta vẫn có thể đạt được điều đó với keyof và một số phép thuật bản thảo. Đây là định nghĩa của hàm:

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

Lưu ý cách sử dụng FeatureBoxResponsiveLayout[string]để chuyển đổi giá trị chuỗi được truyền vào giá trị số của enum.

Điều này sẽ đưa ra một thông báo lỗi với trình biên dịch AOT nếu bạn sử dụng giá trị không hợp lệ.

Đối số của loại '"H4THER"' không thể gán cho tham số của loại '"Dọc" | "Ngang"

Hiện tại VSCode không đủ thông minh để gạch chân H4orizontaltrong trình soạn thảo HTML, nhưng bạn sẽ nhận được cảnh báo vào thời gian biên dịch (với --prod build hoặc --aot switch). Điều này cũng có thể được cải thiện trong một bản cập nhật trong tương lai.


không chắc chắn nếu tôi thích hằng số bên trong htmlnhưng tôi thấy quan điểm của bạn và bắt đầu sử dụng nó; Nó làm công việc, như ngày xưa tốt đẹp, khi biên dịch! :)
tháng

@genuinefafa cách tiếp cận này thực sự là về việc đưa enum ra khỏi html nhưng vẫn cho phép các giá trị enum được biên dịch. Tôi cho rằng bạn có thể nói nó tách html khỏi ts nhưng bản thân nó không mang lại lợi ích thực sự nào vì chúng luôn được sử dụng cùng nhau.
Simon_Weaver

tôi thích kiểm tra loại, đặc biệt trong phát triển không được thử nghiệm tự động
20 tháng

upvote vì dòng mở đầu "Bắt đầu bằng cách xem xét 'Tôi có thực sự muốn làm điều này không?'"
WebDever

2

Thành phần của tôi đã sử dụng một đối tượng myClassObjectcủa loại MyClassmà chính nó đang sử dụng MyEnum. Điều này dẫn đến cùng một vấn đề được mô tả ở trên. Giải quyết nó bằng cách làm:

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

và sau đó sử dụng cái này trong mẫu như

<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

Nếu sử dụng phương pháp 'tham chiếu có thể đánh máy' (từ @Carl G) và bạn đang sử dụng nhiều loại bảng, bạn có thể muốn xem xét theo cách này:

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; 

Sau đó truy cập vào tệp html của bạn với

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

Tôi ủng hộ cách tiếp cận này vì nó cho thấy rõ ràng bạn đang đề cập đến một lỗi đánh máy và cũng tránh ô nhiễm không cần thiết cho tệp thành phần của bạn.

Bạn cũng có thể đặt toàn cầu TTở một nơi nào đó và thêm enum vào nó khi cần thiết (nếu bạn muốn điều này, bạn cũng có thể thực hiện một dịch vụ như được hiển thị bởi câu trả lời @VincentSels). Nếu bạn có nhiều lỗi đánh máy, điều này có thể trở nên cồng kềnh.

Ngoài ra, bạn luôn đổi tên chúng trong tuyên bố của mình để có được một tên ngắn hơn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.