Angular2 ngSwitch deyiminde daktiloda numaralandırma değeri nasıl kullanılır


159

Typescript enum, Angular2'nin ngSwitch yönergesiyle doğal bir eşleşme gibi görünüyor. Ancak bileşenimin şablonunda bir enum kullanmaya çalıştığımda, "undefined öğesinin 'xxx' özelliği okunamıyor ..." iletisini alıyorum. Bileşen şablonumda enum değerlerini nasıl kullanabilirim?

Lütfen bunun bir enum (ngFor) değerinin TÜMÜNÜ temel alan html seçim seçeneklerinin nasıl oluşturulduğundan farklı olduğunu unutmayın. Bu soru, bir numaralandırmanın belirli bir değerine dayanan ngSwitch ile ilgilidir. Her ne kadar enum sınıf içi bir referans oluşturma aynı yaklaşım ortaya çıkıyor.



1
Bu soruların kopya olduğunu sanmıyorum; diğeri ise bir enum (ngFor) değerinin TÜMÜ'ne dayalı HTML seçme seçeneklerinin nasıl oluşturulacağını sorurken, bu bir enum'un belirli bir değerine dayalı ngSwitch ile ilgilidir. Her ne kadar enum sınıf içi bir referans oluşturma aynı yaklaşım ortaya çıkıyor. Benzerliği belirttiğiniz için teşekkür ederiz.
Carl G

Yanıtlar:


166

Bileşen sınıfınızdaki numaralandırmaya bir başvuru oluşturabilirsiniz (ilk karakteri küçük harf olarak değiştirdim) ve sonra bu başvuruyu şablondan ( dalgıç ) kullandım:

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

Numaralandırmalardan haberdar olması için bileşeninize eklemek üzere özel bir dekoratör oluşturabilirsiniz.

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
Herkes bu yöntemi kullanarak AoT derleyici ile başarılı oldu mu?
Danny

2
@Simon_Weaver dekoratörleri temel olarak bir işlevi parametre olarak alan ve bu işlevin davranışını genişleten işlevlerdir. ES6 / 7 durumunda, sınıfların genişletilmesi / ek açıklamasıyla ilgileniyoruz. İşte nasıl çalıştıklarına dair üst düzey bir makale . ES7 içinde uygulanması için öneri github üzerinde - şu anda söz konusu teklifte aşamada 2., onlar dekoratörler için olası kullanımları üzerine dokunun. JS'nin bir üst kümesi olan TypeScript bu özelliği içerir.
Eric Lease

2
@Simon_Weaver Bu durumda, sözdizimsel şeker, örneğin geçirildiği ve bir özelliğinin MyEnumAware()bulunduğu çağrıyı gizler ve prototipine eklenir. Özelliğin değeri enum'un kendisi olarak ayarlanır. Bu yöntem kabul edilen cevapla aynı şeyi yapar. Sadece dekoratörler için önerilen ve TypeScript'te izin verilen sözdizimsel şekerden yararlanıyor. Angular kullanırken, yarasadan dekoratör sözdizimini kullanıyorsunuz. Bu bir ne olduğunu , boş bir sınıfın bir uzantısı açısal ana sınıfları ile etkileşim kuracaklarını bilir. EnumAwareComponentMyEnumComponent
Eric Lease

5
-1: Bu aot ile çalışmıyor gibi görünüyor ERROR in ng:///.../whatever.component.html (13,3): Property 'MyEnum' does not exist on type 'EnumAwareComponent'. Bu mantıklıdır, çünkü dekoratörün eklediği özellik asla bildirilmez ve dizgi derleyicisinin varlığından habersiz kalır.
meriton

2
Bunu 4 aydan fazla kullanıyorum. Ancak, şimdi bir --prodyapı yapıyorum (Ionic 3 / Angular 4 / Typescript 2.4.2) artık çalışmıyor. Hatayı alıyorum "TypeError: Cannot read property 'FirstValue' of undefined". Standart bir sayısal numaralandırma kullanıyorum. AoT ile iyi çalışır, ancak ile değil --prod. HTML'de tamsayıları kullanacak şekilde değiştirirsem işe yarar, ama mesele bu değil. Herhangi bir fikir?
Russ

47

Bu basit ve bir cazibe gibi çalışır :) sadece enum böyle ilan ve HTML şablonunda kullanabilirsiniz

  statusEnum: typeof StatusEnum = StatusEnum;

Araştırma günlerinden sonra nihayet neye ihtiyacım olduğunu buldum. Çok teşekkürler!
gsiradze

@Rahul sınıflardan StatusEnumbirinde tanımlanır .ts. İçeri aktardığınız Açısal bileşende, bir bileşen özelliğine (burada statusEnum) bağlayın ve bileşen özelliklerine şablondan erişilebilir.
tom

tanklar bu harika
hassan khademi

45

Angular4 - HTML Şablonunda Numaralandırma Kullanımı ngSwitch / ngSwitchCase

Burada çözüm: https://stackoverflow.com/a/42464835/802196

kredi: @snorkpete

Bileşeninizde,

enum MyEnum{
  First,
  Second
}

Daha sonra bileşeninizde, 'MyEnum' üyesi aracılığıyla Enum türünü getirirsiniz ve 'myEnumVar' numaralandırma değişkeniniz için başka bir üye yaratırsınız:

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

Artık .html şablonunuzda myEnumVar ve MyEnum'u kullanabilirsiniz. Örn.

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

aynı numaralandırmayı farklı bir bileşende nasıl yeniden kullanabilirsiniz?
ForestG

1
Enum "enum MyEnum {...}" verme kullanarak harici bir dosyada tanımlamak zorunda kaldı. Daha sonra bileşen dosyasında, bu harici dosyadan 'MyEnum'u içe aktarın ve yukarıdaki' MyEnum = MyEnum "vb. İçin çözümle devam edin.
ObjectiveTC

16

rc.6 / final itibariyle

...

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
Ne değişti?
Carl G

ngSwitchCase ile değiştirildi
born2net

Ah tamam. Teşekkürler!
Carl G

14

@Eric Lease'in dekoratörüne alternatif olarak, maalesef --aot(ve böylece --prod) derlemeleri kullanarak çalışmaz , tüm uygulama numaralarını gösteren bir hizmet kullanmaya başvurdum. Bunu gerektiren her bileşene, kolay bir adla herkese açık bir şekilde enjekte etmeniz yeterlidir, daha sonra görünümlerinizdeki numaralara erişebilirsiniz. Örneğin:

Hizmet

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

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

Modülünüzün sağlayıcı listesine eklemeyi unutmayın.

Bileşen sınıfı

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

  // ...
}

Bileşen html

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

Ayrıca hizmet değiştirmek ve @Injectable ({sağlananIn: 'root'}) yazmak için çalışması gerekiyordu. Teşekkürler!
Stalli

2

' Gerçekten bunu yapmak istiyor muyum ?'

Doğrudan HTML içinde numaralandırma atıfta hiçbir sorunum yok, ancak bazı durumlarda tip güvenliğini kaybetmeyen temiz alternatifler vardır. Örneğin, diğer cevabımda gösterilen yaklaşımı seçerseniz, bileşene TT'yi böyle bir şey bildirmiş olabilirsiniz:

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

HTML'nizde farklı bir düzen göstermek *ngIfiçin her düzen türü için bir düzeniniz olur ve doğrudan bileşeninizin HTML'sindeki numaralandırmaya başvurabilirsiniz:

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

Bu örnek, geçerli mizanpajı almak için bir hizmet kullanır, bunu zaman uyumsuz kanal üzerinden çalıştırır ve ardından numaralandırma değerimizle karşılaştırır. Oldukça ayrıntılı, kıvrımlı ve bakmak çok eğlenceli değil. Ayrıca, aşırı derecede ayrıntılı olabilen enumun adını da ortaya koyar.

HTML'den tür güvenliğini koruyan alternatif

Alternatif olarak, aşağıdakileri yapabilir ve bileşeninizin .ts dosyasında daha okunabilir bir işlev bildirebilirsiniz:

*ngIf="isResponsiveLayout('Horizontal')"

Çok daha temiz! Peki ya birisi 'Horziontal'yanlışlıkla girerse ? HTML'de bir numaralandırma kullanmak istemenizin nedeni yazım kurallarına uymaktı değil mi?

Bunu keyof ve bazı daktilo büyüsü ile hala başarabiliriz . Bu fonksiyonun tanımıdır:

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

Kullanımını Not FeatureBoxResponsiveLayout[string]hangi dönüştürür enum sayısal değere geçirilen dize değeri.

Geçersiz bir değer kullanırsanız, AOT derlemesine sahip bir hata iletisi verir.

'"H4orizontal"' türünün bağımsız değişkeni, "" Dikey "türündeki parametreye atanamaz | "Yatay"

Şu anda VSCode, H4orizontalHTML düzenleyicisinde altını çizecek kadar akıllı değildir , ancak derleme zamanında uyarıyı alırsınız (--prod build veya --aot anahtarıyla). Bu, gelecekteki bir güncellemede de geliştirilebilir.


emin değilim eğer içinde sabitleri seviyorum htmlama ben senin noktasını görmek ve kullanmaya başladı; derleme yaparken eski güzel günler gibi iş yapar! :)
genuinefafa

@genuinefafa Bu yaklaşım gerçekten enum kendisini html'den çıkarmak, ancak yine de enum değerlerinin derlenmesini sağlamakla ilgilidir. Html'yi ts'ten ayırdığını söyleyebilirim, ancak kendi başına herhangi bir gerçek fayda sunmuyor çünkü her zaman birlikte kullanılıyorlar.
Simon_Weaver

özellikle otomatik olarak test edilmemiş geliştirme tür kontrol, seviyorum
genuinefafa

"Gerçekten bunu yapmak istiyor muyum?"
düşünerek başlayın.

2

Bileşenim , kendisinin kullandığı myClassObjecttürden bir nesne MyClasskullandı MyEnum. Bu, yukarıda açıklanan aynı soruna yol açar. Yaparak çözüldü:

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

ve sonra bunu şablonda

<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

'Yazılabilir referans' yaklaşımını (@Carl G'den) kullanıyorsanız ve birden çok tür tablo kullanıyorsanız şu şekilde düşünmek isteyebilirsiniz:

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; 

Sonra ile html dosyanıza erişin

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

Bu yaklaşımı, bir yazı tipinden bahsettiğinizi açıklığa kavuşturduğundan ve bileşen dosyanızın gereksiz kirliliğinden kaçındığından eminim.

Ayrıca bir TTyere bir küresel koymak ve gerektiği gibi numaralandırmalar ekleyebilirsiniz (bunu istiyorsanız @VincentSels cevap gösterildiği gibi bir hizmet de yapabilirsiniz). Çok sayıda yazı tipiniz varsa, bu hantal olabilir.

Ayrıca, daha kısa bir ad almak için her zaman beyanınızda onları yeniden adlandırırsınız.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.