Select based on enum in Angular2

前端 未结 11 2021
别那么骄傲
别那么骄傲 2020-11-28 23:26

I have this enum (I\'m using TypeScript) :

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

I would like to build a

相关标签:
11条回答
  • 2020-11-28 23:43

    update2 simplified by creating an array

    @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;
    }
    

    update

    instead of pipes: [KeysPipe]

    use

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

    original

    Using the keys pipe from https://stackoverflow.com/a/35536052/217408

    I had to modify the pipe a bit to make it work properly with enums (see also How to get names of enum entries?)

    @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

    See also How to iterate object keys using *ngFor?

    0 讨论(0)
  • 2020-11-28 23:44

    Another spin off of this answer, but this actually maps the values as numbers, instead of converting them to strings which is a bug. It also works with 0 based enums

    @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));;
      }
    }
    
    0 讨论(0)
  • 2020-11-28 23:46

    With string enums you can try this.

    My string enum has the following definition:

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

    and translates to js in the following way:

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

    I have a few of these in my project so created small helper function in a shared service lib:

       @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 your component constructor and Bind it to your template like this:

    In component:

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

    In template:

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

    Don't forget to add the UtilsService to the provider array in your app.module.ts so you can easily inject it in different components.

    I'm a typescript newbie so please correct me if I'm wrong or if there are better solutions.

    0 讨论(0)
  • 2020-11-28 23:53

    I've preferred to have a simple utility function shared across my Angular App, to convert the enum into a standard array to build selects:

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

    to fill a variable in the Component with:

    public countries = enumSelector(CountryCodeEnum);
    

    and then fill my Material Select as my old array based ones:

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

    Thanks for this thread!

    0 讨论(0)
  • 2020-11-28 23:54

    One more solution if you don't want to create a new pipe. You could also extract keys into helper property and use it:

    @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

    Edit:

    if you need the options as numbers instead of strings:

    • replace [value] with [ngValue]
    • add .map(Number) after .filter(...)
    0 讨论(0)
提交回复
热议问题