1

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"
/>

1 Answer 1

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>
Sign up to request clarification or add additional context in comments.

3 Comments

Wow.. that works! ( :value="option[optionVal]" ). Thank You! I was definitely overthinking this one. Can you explain how it still works without naming optionVal & optionName when the options DO have the right obj keys?
we have two ways to access object properties by . (dot) or by [] like user.name or user["name"], so i used the second when since it's dynamical
Ahh, I see what you did with the prop defaults ('name' and 'value').. that's why it was still working without me setting a value for optionVal. Great job and thanks again!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.