vue.jsvuejs3v-modelvue-reactivity

Set default option for dropdown and assign value in VueJS


I have 2 dropdowns that are connected. You select a language in the first dropdown and a list of voices associated with that language will appear in the second dropdown.

I want to set a default value to load in the first dropdown when I first load the page because on load it's empty.

In the view, I've set :value="language" but this is returning object Object in the HTML markup. If I set it to language.id the voices stop appearing.

enter image description here

All I want to do is set "English" as the default option when the page loads and retrieve the correct voices for the selected language.

Also, is there a better way to populate the default voice for each language instead of setdropdown() because that will get really long if I have 10s of languages.

data() {
    return {
        selected: '',
        selectedVoice: '',
        languages: [{
                "id": 1,
                "name": "English",
                "voices": [
                    {
                        "id": "en-jenny",
                        "name": "Jenny"
                    },
                    {
                        "id": "en-davis",
                        "name": "Davis"
                    }
                ]
            },
            {
                "id": 2,
                "name": "Spanish",
                "voices": [
                    {
                        "id": "es-lupe",
                        "name": "Lupe"
                    },
                    {
                        "id": "es-juan",
                        "name": "Juan"
                    },
                    {
                        "id": "es-miguel",
                        "name": "Miguel"
                    }
                ]
            }
        ],
    }
},

methods: {
    setdropdown() {
        if (this.selected.name == 'English') this.selectedVoice = 'en-jenny'
        else if (this.selected.name == 'Spanish') this.selectedVoice = 'es-lupe'
    }
},

And this is the view.

<select v-model="selected" class="form-control" @change="setdropdown()">
    <option v-for="(language, index) of languages" :key="index" :value="language">{{ language.name }}</option>
</select>

<select v-model="selectedVoice" class="form-control">
    <option v-for="(voice, index) of selected.voices" :key="index" :value="voice.id">{{ voice.name }}</option>
</select>

Solution

  • Try this approach:

    <script>
    export default {
      data() {
          return {
              selected: 1,
              selectedVoice: 'en-jenny',
              languages: [{
                      "id": 1,
                      "name": "English",
                      "voices": [
                          {
                              "id": "en-jenny",
                              "name": "Jenny"
                          },
                          {
                              "id": "en-davis",
                              "name": "Davis"
                          }
                      ]
                  },
                  {
                      "id": 2,
                      "name": "Spanish",
                      "voices": [
                          {
                              "id": "es-lupe",
                              "name": "Lupe"
                          },
                          {
                              "id": "es-juan",
                              "name": "Juan"
                          },
                          {
                              "id": "es-miguel",
                              "name": "Miguel"
                          }
                      ]
                  }
              ],
          }
      },
       
      computed: {
        selectedVoices() {
          let selectedLanguage = this.languages.find(language => language.id === this.selected);
          return typeof selectedLanguage.voices !== 'undefined' ? selectedLanguage.voices : [];
        }
      },
      
      methods: {
        setDefaultValue() {
          this.selectedVoice = this.selectedVoices[0].id;
        }
      }
    
     }
    </script>
    
    <template>
      <div>
        <select v-model="selected" class="form-control" @change="setDefaultValue">
            <option v-for="language in languages" :key="language.id" :value="language.id">{{ language.name }}</option>
        </select>
    
        <select v-model="selectedVoice" class="form-control">
            <option v-for="voice in selectedVoices" :key="voice.id" :value="voice.id">{{ voice.name }}</option>
        </select>
      </div>
    </template>
    

    Few comments:

    1. I suggest you use computed instead of method for getting voices
    2. You can set the default value in data or in mounted hook
    3. Don't use index as key, this is not recommend and can have impact to performance, instead use some property of an iterated object