vue.jsfiltervue-select

How to create a multiple options from a single data coming from the API for displaying it as a select/dropdown in VueJS


I am trying to display the select drop down using vs-select, the options are taken from the API. Here is my scenario I have made all my components dynamic, i have 3 cards in my front page, if I click any of the card respective contents are displayed.

Here is the response that I get from the /my-project endpoint:

    [
          {
            "uid": 1,
            "choice": "project_title1|project_title2|project_title3",
            "age": "35",
            "country": "india"
          },
          {
            "uid": 2,
            "choice": "project_title2",
            "age": "25",
            "country": "australia"
          } 
          ...
    ]

Here is my code:

        <span v-if="out.choice">
            <template  v-for="(val, e) in Myfilter(out.choice)">
                <vs-select v-model="check" :key="e" :options="[{label: val}]" />
            </template>
        </span>
        <div v-if="out.choice === 'project_title1'">     
           --show contents1--
        </div>
        <div v-if="out.choice === 'project_title2'">
           --show contents2--
        </div>
    check: null,
    out: null
    // ...
    methods: {
      Myfilter (val){
      return val.replaceAll('_', ' ').split('|')
    },
      SelectVue (id) {
          this.$http.get(`/my-project/${id}`)
            .then((res) => {this.out= res.data})
        }
      },
    mounted (){
      this.SelectVue (this.$route.params.uid)
    }

If the user clicks on 2nd card he will get the details of uid=2 i.e in vue-select he will get the option as project title2. If the user clicks on 1st card he will get the details of uid=1 then three vue-select are displayed as shown in image:

enter image description here

Rather i want a single vue-select and three different options in it as:

enter image description here

Here is my question: How do i have a single vue-select for the data coming from API and then display different options for it.


Solution

  • In order to save the selection you have to map an additional property to each of your API entries. I called it selection in the following example. I also made a computed extracting the user selection from entries.

    Note I also named choice in each item to choices (makes more sense to me).

    Vue.config.productionTip = false;
    Vue.config.devtools = false;
    new Vue({
      el: '#app',
      data: () => ({
        entries: [{
            "uid": 1,
            "choices": "project_title1|project_title2|project_title3",
            "age": "35",
            "country": "india"
          },
          {
            "uid": 2,
            "choices": "project_title2",
            "age": "25",
            "country": "australia"
          }
        ].map(el => ({...el, selection: null }))
    /* Entries need to have a `selection` with a value other than `undefined` before 
     * being passed to Vue's data. Otherwise `.selection` on each won't be reactive
     */
      }),
      computed: {
        selection() {
          return Object.assign({}, ...this.entries.map(e => ({
            [e.country]: e.selection
          })));
        }
      },
      methods: {
        makeSelectOptions(choices) {
          return choices.split('|').map(value => ({
            text: value,
            value
          }))
        }
      }
    })
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vuesax@3.12.2/dist/vuesax.umd.min.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/vuesax/dist/vuesax.css" rel="stylesheet"/>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/material-design-icons/3.0.2/iconfont/material-icons.min.css" rel="stylesheet"/>
    
    <div id="app">
      <div v-for="(entry, index) in entries">
        <vs-select :label="entry.country"
                   v-model="entry.selection">
          <vs-select-item :key="index"
                          v-bind="item"
                          v-for="(item,index) in makeSelectOptions(entry.choices)" />
        </vs-select>
      </div>
      <pre v-text="selection"></pre>
    </div>

    Turning choices into selection options is handled by the makeSelectOptions method.