John
John

Reputation: 95

Allow Vue2 Select Component to take in any array for select options

I'm trying to create a reusable Select component that will work with any Array passed to it as options.

I have it working if the Object properties in the array share the same names bound in the component, but if you pass an array of objects that have different property/attribute names, as expected, the options will not render. How can I assign on the component which object property I want as the option value and which I want as the option label/name?

FormSelect.vue / Component

<template>
   <select :id="id" v-model="selected">     
      <option v-if="options.length > 0" value="">Please Select</option>
      <option
        v-if="options.length > 0"
        v-for="(option, index) in options"
        :key="index"
        :selected="selected"
        :value="option.value"
        v-text="option.name"
       />  

    </select>
</template>
<script>
props: {
 value: {    
      type: [Array, String, Number, Object],
      default: null
    },
 options: {
      type: Array,
      default: () => []
    }
},

computed: {
    selected: {
      get() {
        return this.value ? this.value : "";
      },
      set(v) {
        this.$emit("input", v);
      }
    }
  }
</script>

Parent.vue / Parent

<form-select
   id="gender"
   label="Gender"
   :options="genderOptions"
   @input="handleEdit(deep(profile))"
   v-model="user.gender"
/>

This works:

genderOptions: [
  { name: "Male", value: "MALE" },
  { name: "Female", value: "FEMALE" }
],

This would not (notice obj key names):

genderOptions: [
    { id: "Male", gender: "MALE" },
    { id: "Female", gender: "FEMALE" }
 ],

So I'm thinking there needs to be a way to tell the component which properties I want to use as the option value and label. Something like this, but then it would also need to be handles on the component side:

<form-select
   id="gender"
   label="Gender"
   :options="genderOptions"

   optionVal="gender"
   optionName="id"

   @input="handleEdit(deep(profile))"
   v-model="user.gender"
/>

Upvotes: 1

Views: 877

Answers (1)

Boussadjra Brahim
Boussadjra Brahim

Reputation: 1

You're missing to add optionVal and optionName props to your component and to work with them, i suggest the following solution

<script>
props: {
 value: {    
      type: [Array, String, Number, Object],
      default: null
    },
 options: {
      type: Array,
      default: () => []
    },
optionVal:{
    type:String,
    default: 'value'
    },
optionName:{
    type:String,
    default: 'name'
    }
},

computed: {
    selected: {
      get() {
        return this.value ? this.value : "";
      },
      set(v) {
        this.$emit("input", v);
      }
    }
  }
</script>
 <select :id="id" v-model="selected">     
      <option v-if="options.length > 0" value="">Please Select</option>
      <option
        v-if="options.length > 0"
        v-for="(option, index) in options"
        :key="index"
        :selected="selected"
        :value="option[optionVal]"
    v-text="option[optionName]"
       />  

    </select>

Upvotes: 1

Related Questions