Search code examples
angulartypescriptangular6

Use enum in angular to select drop menu item


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


Solution

  • I usually do it in 3 steps.

    First, declare a separate enum and a mapping from the enum values to labels. 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.

    So it looks like you have to additionally filter your array

    public stateTypes = Object.values(MerchantStateType).filter(value => typeof value === 'number');