Wählen Sie basierend auf der Aufzählung in Angular2

77

Ich habe diese Aufzählung (ich verwende TypeScript ):

export enum CountryCodeEnum {
    France = 1,
    Belgium = 2
}

Ich möchte in meinem Formular eine Auswahl erstellen , wobei für jede Option der Enum-Integer-Wert als Wert und der Enum-Text als Beschriftung wie folgt verwendet werden:

<select>
     <option value="1">France</option>
     <option value="2">Belgium</option>
</select>

Wie kann ich das machen ?

AdrienTorris
quelle

Antworten:

61

update2 durch Erstellen eines Arrays vereinfacht

@Pipe({name: 'enumToArray'})
export class EnumToArrayPipe implements PipeTransform {
  transform(value) : Object {
    return Object.keys(value).filter(e => !isNaN(+e)).map(o => { return {index: +o, name: value[o]}});
  }
}

@Component({
  ...
  imports: [EnumsToArrayPipe],
  template: `<div *ngFor="let item of roles | enumToArray">{{item.index}}: {{item.name}}</div>`
})
class MyComponent {
  roles = Role;
}

aktualisieren

anstatt pipes: [KeysPipe]

verwenden

@NgModule({
  declarations: [KeysPipe],
  exports: [KeysPipe],
}
export class SharedModule{}
@NgModule({
  ...
  imports: [SharedModule],
})

Original

Verwenden der keysPipe von https://stackoverflow.com/a/35536052/217408

Ich musste die Pipe ein wenig ändern, damit sie mit Aufzählungen ordnungsgemäß funktioniert (siehe auch So erhalten Sie Namen von Aufzählungseinträgen? )

@Pipe({name: 'keys'})
export class KeysPipe implements PipeTransform {
  transform(value, args:string[]) : any {
    let keys = [];
    for (var enumMember in value) {
      if (!isNaN(parseInt(enumMember, 10))) {
        keys.push({key: enumMember, value: value[enumMember]});
        // Uncomment if you want log
        // console.log("enum member: ", value[enumMember]);
      } 
    }
    return keys;
  }
}

@Component({ ...
  pipes: [KeysPipe],
  template: `
  <select>
     <option *ngFor="let item of countries | keys" [value]="item.key">{{item.value}}</option>
  </select>
`
})
class MyComponent {
  countries = CountryCodeEnum;
}

Plunker

Siehe auch So iterieren Sie Objektschlüssel mit * ngFor?

Günter Zöchbauer
quelle
2
Ich werde eine weitere Änderung in der Reihenfolge der Bindung an work keys.push hinzufügen ({key: parseInt (enumMember, 10), value: value [enumMember]});
Mihail
@Component({ imports:;; EnumToArrayPipe! = EnumToArrayPipes;-)
Martin Schneider
63

Eine weitere Lösung, wenn Sie keine neue Pipe erstellen möchten. Sie können auch Schlüssel in die Hilfseigenschaft extrahieren und verwenden:

@Component({
  selector: 'my-app',
  providers: [],
  template: `
    <div>
      <select>
        <option *ngFor="let key of keys" [value]="key" [label]="countries[key]"></option>
      </select>
    </div>
  `,
  directives: []
})
export class App {

  countries = CountryCodeEnum

  constructor() {
    this.keys = Object.keys(this.countries).filter(k => !isNaN(Number(k)));
  }
}

Demo: http://plnkr.co/edit/CMFt6Zl7lLYgnHoKKa4E?p=preview

Bearbeiten:

Wenn Sie die Optionen als Zahlen anstelle von Zeichenfolgen benötigen :

  • ersetzen [value]durch[ngValue]
  • .map(Number)nachher hinzufügen.filter(...)
dfsq
quelle
1
Ich habe das Etikett in der Dropdown-Liste nicht gesehen, daher habe ich die Optionszeile geändert in: <option *ngFor="#key of keys" [value]="key">{{countries[key]}}</option>
Hans Beemsterboer
23
Wenn Ihre Aufzählung mit 0 beginnt, funktioniert sie nicht. Es ist besser zu verwenden: Object.keys (CountryCodeEnum) .filter (k =>! IsNaN (Number (k)));
Oleg
1
Wenn Sie mit 0 beginnen, ist dies ein schlechter Ansatz. Wenn Object.keys (this.countries) ["0", "1", "2", "NotSet", "EU", "US"] zurückgibt, lässt der Filter "0" weg, sodass das gefilterte Ergebnis angezeigt wird ["1", "2"]. Nicht ["0", "1", "2"] wie ich es erwarten würde.
Tomino
1
Zusätzlich zu der Modifikation von @ Oleg schlage ich vor, sie anzuhängen .map(Number), um eine Rückerstattung zu erhalten number[]. Dies dient dazu, Probleme beim Binden einer Eigenschaft an die keyund das Erwarten eines number(statt eines string) Zurücks in Ihrer Komponente zu vermeiden .
Dillon Ryan Redding
20

Hier ist ein sehr einfacher Weg für Angular2 v2.0.0. Der Vollständigkeit halber habe ich ein Beispiel für die Festlegung eines Standardwerts für die countryAuswahl über reaktive Formulare beigefügt .

@Component({
  selector: 'my-app',
  providers: [],
  template: `
    <div>
      <select id="country" formControlName="country">
        <option *ngFor="let key of keys" [value]="key">{{countries[key]}}</option>
      </select>
    </div>
  `,
  directives: []
})
export class App {
  keys: any[];
  countries = CountryCodeEnum;

  constructor(private fb: FormBuilder) {
    this.keys = Object.keys(this.countries).filter(Number);
    this.country = CountryCodeEnum.Belgium; //Default the value
  }
}
rynop
quelle
Sie müssen die Hälfte der Werte herausfiltern, wie von dfsq vorgeschlagen: Object.keys (this.countries) .filter (Number);
AFD
1
Wenn Sie mit 0 beginnen, ist dies ein schlechter Ansatz. Wenn Object.keys (this.countries) ["0", "1", "2", "NotSet", "EU", "US"] zurückgibt, lässt der Filter "0" weg, sodass das gefilterte Ergebnis angezeigt wird ["1", "2"]. Nicht ["0", "1", "2"] wie ich es erwarten würde.
Tomino
Die Leute scheinen zu vergessen, die Werte wieder der Zahl zuzuordnen, bevor sie für die korrekte Antwortprüfung unten verwendet werden
Johnny, 5.
13

Ich habe es vorgezogen, eine einfache Dienstprogrammfunktion in meiner Angular App gemeinsam zu nutzen, um das enumin ein Standardarray zu konvertieren , um Auswahlen zu erstellen:

export function enumSelector(definition) {
  return Object.keys(definition)
    .map(key => ({ value: definition[key], title: key }));
}

So füllen Sie eine Variable in der Komponente mit:

public countries = enumSelector(CountryCodeEnum);

und fülle dann meine Materialauswahl als meine alten Array-basierten aus:

<md-select placeholder="Country" [(ngModel)]="country" name="country">
  <md-option *ngFor="let c of countries" [value]="c.value">
    {{ c.title }}
  </md-option>
</md-select>

Danke für diesen Thread!

Mateo Tibaquira
quelle
Wie sieht Ihre CountryCodeEnum aus?
Phhbr
@phhbr Ich glaube, ich habe nicht numerische Werte verwendet, wie:export enum CountryCodeEnum { France = '1', Belgium = '2' }
Mateo Tibaquira
Das Objekt von CountryCodeEnum sieht ungefähr so ​​aus, wenn Sie Ihre Aufzählung verwenden: [1: "Frankreich", 2: "Belgien", Frankreich: 1, Undefiniert: 2,]
phhbr
7

Eine andere ähnliche Lösung, bei der "0" nicht weggelassen wird (wie "Unset"). Die Verwendung von Filter (Nummer) IMHO ist kein guter Ansatz.

@Component({
  selector: 'my-app',
  providers: [],
  template: `
  <select>
    <option *ngFor="let key of keys" [value]="key" [label]="countries[key]"></option>
  </select>`,
  directives: []
})

export class App {
  countries = CountryCodeEnum;

  constructor() {
    this.keys = Object.keys(this.countries).filter(f => !isNaN(Number(f)));
  }
}

// ** NOTE: This enum contains 0 index **
export enum CountryCodeEnum {
   Unset = 0,
   US = 1,
   EU = 2
}
Tomino
quelle
Danke vielmals! das half
Bellash
4

Ab Angular 6.1 und höher können Sie das integrierte Beispiel KeyValuePipewie unten verwenden (aus Angular.io-Dokumenten eingefügt).

Ich gehe davon aus, dass eine Aufzählung natürlich menschlich lesbare Zeichenfolgen enthält :)

@Component({
  selector: 'keyvalue-pipe',
  template: `<span>
    <p>Object</p>
    <div *ngFor="let item of object | keyvalue">
      {{item.key}}:{{item.value}}
    </div>
    <p>Map</p>
    <div *ngFor="let item of map | keyvalue">
      {{item.key}}:{{item.value}}
    </div>
  </span>`
})
export class KeyValuePipeComponent {
  object: {[key: number]: string} = {2: 'foo', 1: 'bar'};
  map = new Map([[2, 'foo'], [1, 'bar']]);
}

Samuel R.
quelle
3

Ein weiterer Nebeneffekt dieser Antwort, aber dies ordnet die Werte tatsächlich als Zahlen zu, anstatt sie in Zeichenfolgen umzuwandeln, was ein Fehler ist. Es funktioniert auch mit 0-basierten Aufzählungen

@Component({
  selector: 'my-app',
  providers: [],
  template: `
  <select>
<option *ngFor="let key of keys" [value]="key" [label]="countries[key]"></option>
  </select>`,
  directives: []
})

export class App {
  countries = CountryCodeEnum;

  constructor() {
    this.keys = Object.keys(this.countries)
                      .filter(f => !isNaN(Number(f)))
                      .map(k => parseInt(k));;
  }
}
Johnny 5
quelle
1

Mit String-Enums können Sie dies versuchen.

Meine String-Enumeration hat folgende Definition:

    enum StatusEnum {
        Published = <any> 'published',
        Draft = <any> 'draft'
    }

und übersetzt auf folgende Weise in js:

   {
       Published: "published", 
       published: "Published", 
       Draft: "draft", 
       draft: "Draft"
   }

Ich habe einige davon in meinem Projekt, also habe ich eine kleine Hilfsfunktion in einer Shared Service Lib erstellt:

   @Injectable()
   export class UtilsService {
       stringEnumToKeyValue(stringEnum) {
           const keyValue = [];
           const keys = Object.keys(stringEnum).filter((value, index) => {
               return !(index % 2);
           });

           for (const k of keys) {
               keyValue.push({key: k, value: stringEnum[k]});
           }

           return keyValue;
       }
   }

Init in Ihrem Komponentenkonstruktor und binden Sie es wie folgt an Ihre Vorlage:

In Komponente:

    statusSelect;

    constructor(private utils: UtilsService) {
        this.statusSelect = this.utils.stringEnumToKeyValue(StatusEnum);
    }

In Vorlage:

    <option *ngFor="let status of statusSelect" [value]="status.value">
        {{status.key}}
    </option>

Vergessen Sie nicht, den UtilsService dem Provider-Array in Ihrer app.module.ts hinzuzufügen, damit Sie ihn problemlos in verschiedene Komponenten einfügen können.

Ich bin ein Typoskript-Neuling. Bitte korrigieren Sie mich, wenn ich falsch liege oder wenn es bessere Lösungen gibt.

Christopher
quelle
Ich musste den Filter für gerade / ungerade Indizes entfernen, damit meine funktionieren
Reggaeguitar
0

Dies ist die beste Option, die Sie ohne Pipes oder zusätzlichen Code anwenden können.

import { Component } from '@angular/core';

 enum AgentStatus {
    available =1 ,
    busy = 2,
    away = 3,
    offline = 0
}


@Component({
  selector: 'my-app',
  template: `
  <h1>Choose Value</h1>

  <select (change)="parseValue($event.target.value)">
    <option>--select--</option>
    <option *ngFor="let name of options"
        [value]="name">{{name}}</option>
  </select>

  <h1 [hidden]="myValue == null">
    You entered {{AgentStatus[myValue]}}

  </h1>`
})
export class AppComponent { 


  options : string[];
  myValue: AgentStatus;
  AgentStatus : typeof AgentStatus = AgentStatus;

  ngOnInit() {
    var x = AgentStatus;
    var options = Object.keys(AgentStatus);
    this.options = options.slice(options.length / 2);
  }

  parseValue(value : string) {
    this.myValue = AgentStatus[value];

  }
}
Nimish Goel
quelle
0

Noch eine Lösung mit Angular 6.1.10 / Typescript ...

 enum Test {
   No,
   Pipe,
   Needed,
   Just,
   Use,
   Filter
 }

 console.log('Labels: ');
 let i = 0;
 const selectOptions = [
    ];
 Object.keys(Test).filter(key => !Number(key) && key !== '0').forEach(key => {
    selectOptions.push({position: i, text: key});
    i++;
  });
 console.log(selectOptions);

Dies wird gedruckt:

Console:
Labels: 
    (6) [{…}, {…}, {…}, {…}, {…}, {…}]
    0: {position: 0, text: "No"}
    1: {position: 1, text: "Pipe"}
    2: {position: 2, text: "Needed"}
    3: {position: 3, text: "Just"}
    4: {position: 4, text: "Use"}
    5: {position: 5, text: "Filter"}
Stefan B.
quelle
0
export enum Unit
{
    Kg = 1,
    Pack,
    Piece,
    Litre
}

// mit Karte

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'enumToArray'
})
export class EnumToArrayPipe implements PipeTransform {

  transform(enumObj: Object) {

    const keys = Object.keys(enumObj).filter(key => parseInt(key));
    let map = new Map<string, string>();
    keys.forEach(key => map.set(key, enumObj[key]))
    console.log( Array.from(map));
    return Array.from(map);
  }

}

// Mit set

    import { Pipe, PipeTransform } from '@angular/core';

    @Pipe({
      name: 'enumToArray'
    })
    export class EnumToArrayPipe implements PipeTransform {

      transform(enumObj: Object) {

        const keys = Object.keys(enumObj).filter(key => parseInt(key));
        let set = new Set();
        keys.forEach(key => set.add({ key: parseInt(key), value: enumObj[key] }))
        return Array.from(set);
      }

    }
Sandip Shelke
quelle