16

I want to implement select menu which uses enum data to display data and saved number based on the selected String:

HTML code:

<div class="form-group state_raw">
    <label for="state_raw">State</label>
    <select class="custom-select" name="state_raw" [(ngModel)]="merchant.state_raw" id="state_raw" required>
      <option selected></option>
      <option [value]="type" *ngFor="let type of types">{{type | formatType}}</option>
    </select>
  </div>

Enum which displaying data and translated number value:

export enum MerchantStatusType {
  'Being set up' = 1,
  'Live for processing' = 2,
  'Trading suspended' = 3,
  'Account suspended' = 4
}

Object for the elect menu:

export class MerchantNew {
  constructor(
    public name: string,
    public address_state: string,
  ) {}
}

How can this be implemented? I want to display String but save number into database?

EDIT: I tried this:

ENUM:

export enum MerchantStateType {
  being_set_up = 1,
  live_for_processing = 2,
  trading_suspended = 3,
  account_suspended = 4,
}

export const MerchantStateType2LabelMapping = {
  [MerchantStateType.being_set_up]: "Being set up",
  [MerchantStateType.live_for_processing]: "Live for processing",
  [MerchantStateType.trading_suspended]: "Trading suspended",
  [MerchantStateType.account_suspended]: "Account suspended",
}

Component:

public MerchantStateType2LabelMapping = MerchantStateType2LabelMapping;

public stateTypes = Object.values(MerchantStateType);

HTML code:

<select class="custom-select" name="state_raw" [(ngModel)]="merchant.state_raw" id="state_raw" required>
      <!--<option selected></option>-->
      <option [value]="stateType" *ngFor="let stateType of stateTypes">{{ MerchantStateType2LabelMapping[stateType] }}</option>

But I get 4 empty rows and 4 lines of the states.

enter image description here

Peter Penzov
  • 1,126
  • 134
  • 430
  • 808

3 Answers3

37

I usually do it in 3 steps.

First, declare separate enum and a mapping from enum value to label. This way both enum values and labels can be later changed just in one place without changing any other code.

// FileTypes.enum.ts

export enum FileTypesEnum {
    CSV = "CSV",
    JSON = "JSON",
    XML = "XML",
}

// optional: Record type annotation guaranties that 
// all the values from the enum are presented in the mapping
export const FileType2LabelMapping: Record<FileTypesEnum, string> = {
    [FileTypesEnum.CSV]: "Here's Csv",
    [FileTypesEnum.JSON]: "Here's Json",
    [FileTypesEnum.XML]: "Here's Xml",
};

Then import them into a component and stick them in a public property, so they will be available in the view:

// my.component.ts

import {FileTypesEnum, FileType2LabelMapping} from "../FileTypes.enum";

@Component({ ... })
export class MyComponent implements OnInit {
    public FileType2LabelMapping = FileType2LabelMapping;

    public fileTypes = Object.values(FileTypesEnum);

    constructor(){}
}

And then in the view i'm doing ngFor over enum's values and map them to labels:

 <!-- my.component.html -->

 <select ...>
  <option *ngFor="let fileType of fileTypes"
          [value]="fileType">
    {{FileType2LabelMapping[fileType]}}
  </option>
</select>

Update:

String-valued and numeric enums compile to different objects Typescript Playground

So it looks like you have to additionally filter your array

public stateTypes = Object.values(MerchantStateType).filter(value => typeof value === 'number');
Evgeniy Malyutin
  • 1,329
  • 12
  • 16
  • Thanks but I have a several words for key "Being set up" and you have CSV. How I can use it? – Peter Penzov Dec 08 '18 at 21:16
  • @PeterPenzov You can put this stuff in the label mapping and use a simple one-word identifier for enum key for easy-to-use – Evgeniy Malyutin Dec 08 '18 at 22:50
  • 1
    I found a bug. I get 4 empty lines and 4 values into the drop down list. Are you sure that your code is working properly? – Peter Penzov Dec 08 '18 at 22:55
  • @PeterPenzov I don't understand what whis means "But I get 4 empty rows and 4 lines of the states." Can you take a screenshot? – Evgeniy Malyutin Dec 08 '18 at 23:04
  • @PeterPenzov oh, I see. That's because I usually use string valued enums, not 1, 2, 3 You can see that they compile to the different shape. (My link is too long for a comment, so I'll add it to the answer, click Run and check the console). So you have to account for this shape when declaring `public stateTypes =` – Evgeniy Malyutin Dec 08 '18 at 23:12
  • Can you update the post please in order to handle enum with number, please? – Peter Penzov Dec 08 '18 at 23:17
  • You must filter your array. Something like this `public stateTypes = Object.values(MerchantStateType).filter(value => typeof value === 'number');` – Evgeniy Malyutin Dec 08 '18 at 23:22
  • @PeterPenzov looks like it's a pretty common solution https://stackoverflow.com/a/51536142/2036886 – Evgeniy Malyutin Dec 08 '18 at 23:29
  • Ok, thanks. Do you know how I can display the first value by default? – Peter Penzov Dec 08 '18 at 23:39
20

Another simple way for Making Enum into dropdown or selecct List,

  1. Define Enum
export enum ConditionalOperator {
    Equals="Equals",
    NEquals="NEquals", 
    GT="GT", 
    GTE="GTE", 
    LT="LT", 
    }
  1. In component assign enum to a variable and in the constructor take all enum keys to another defined array
    conditionalOperator = ConditionalOperator;
    enumKeys=[];
    
    constructor(private fb: FormBuilder) {
      this.enumKeys=Object.keys(this.conditionalOperator);
    }
  1. And in the HTML file simply iterate through enum keys is an assign value as following,
    <select>
    <option value='' disabled selected>Operator</option>
    <option *ngFor="let name of enumKeys" [value]="name"> {{conditionalOperator[name]}} </option>
    </select>
mramsath
  • 657
  • 6
  • 12
  • 1
    this didn't work for me. First I had this error at `enumKeys=[]`: Type 'string[]' is not assignable to type 'never[]'.   Type 'string' is not assignable to type 'never'. If I change the line to `enumKeys: string[] = []` then I get this error on server start: `conditionalOperator[name]` gives error: No index signature with a parameter of type 'string' was found on type 'typeof ConditionalOperator'. – Chris Nov 28 '22 at 12:53
  • i had to add keyvalue pipe to the enum and use name.value to make it work – Francesco Rogo Feb 10 '23 at 10:40
0

if anyone using NG-ZORRO template.

Follow the above solution[Click], written by @mramsath

Then try this:

Update constructor or leave as it is. i updated for fetching values.

constructor(private fb: FormBuilder) {
      this.enumKeys=Object.values(this.conditionalOperator);
    }

Here is the main part:

<nz-select name="yourFormPostName" #yourFormPostName="ngModel" [(ngModel)]="data.yourFormPostName" nzPlaceHolder="Select Type" nzAllowClear style="width: 95%;">
<nz-option nzDisabled nzLabel="Select" nzValue="disabled"></nz-option>
<nz-option *ngFor="let name of enumKeys" [nzValue]="name" [nzLabel]="name"> </nz-option>
</nz-select>
Maizied Hasan Majumder
  • 1,197
  • 1
  • 12
  • 25