javascriptvue.jsvuejs3vue-multiselect

add more dynamic drop-down with vue-multiselect


i'm trying to build add more options with vue-multiselect

The following problems i'm facing are:

  1. not able to select multiple tags for states
  2. not able to remove selected tags for states
  3. old values are coming back on click of plus button
  4. dynamic v-model="" is not working correctly

here is a problem giff https://i.sstatic.net/9mTd0.jpg

Here is a codepen link for better visibility: https://codepen.io/eabangalore/pen/WNjRXym?editors=1010

here is what i have tried:

var app = new Vue({
  el: '#app',
  components: { Multiselect: window.VueMultiselect.default },
  data () {
    return {
      addMoreOptionsList:[],
      dynamicAddedOptionsHashMap:{},
      value: [],
      options: [
                 {
                   "country": "America",
                   "states":['CA','MA'],
                   id:'111',
                 },
                 {
                   "country": "India",
                   "states":['KA','MH'],
                   id:'22222'
                 },
        
                  {
                   "country": "West Indies",
                   "states":['West Indies1','West Indies2'],
                    id:'3333'
                 },
        ]
    }
  },
  methods:{
        addMoreItems(){
          this.addMoreOptionsList.push('1 more added');
        },
        removeAll(){
          this.addMoreOptionsList = [];
        },
        countrySelected(options){
           //console.log('options',options);
          if(!Object.hasOwnProperty.call(this.dynamicAddedOptionsHashMap,options.id))
                    this.dynamicAddedOptionsHashMap[options.id] = {options:[],values:[]};
                    
         
         
           this.dynamicAddedOptionsHashMap[options.id]['options'] = options.states;
        }
    }
})
body { font-family: 'Arial' } 

.dropdown-item{
  display:flex;justify-content:space-between;margin-left:20px;
  margin-top:20px;
}
<!DOCTYPE HTML>
<html>
<head>
  <title>Timeline</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="https://unpkg.com/vue-multiselect@2.1.0"></script>
  <link rel="stylesheet" href="https://unpkg.com/vue-multiselect@2.1.0/dist/vue-multiselect.min.css">
  <script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
</head>

<body>
<div id="app">

  <div style="display: flex; margin-bottom: 20px; text-align: end; justify-content: flex-end;"><button style="margin-right:20px;" @click="removeAll()">X</button><button @click="addMoreItems()">+</button></div>
  
<div class="dropdown-item" v-if="addMoreOptionsList.length" v-for="(item,index) in addMoreOptionsList">
  <multiselect
    v-model="value[index]"
    placeholder="Country?"
    label="country"
    :options="options"
    :multiple="false"
    :taggable="false"
    @select="countrySelected($event)"
  ></multiselect>
 
  
   <multiselect style="margin-left:20px;"
    v-if="value[index] && dynamicAddedOptionsHashMap[value[index].id]"
    v-model="dynamicAddedOptionsHashMap[value[index].id].values"
placeholder="States?"    
   :options="dynamicAddedOptionsHashMap[value[index].id].options"
    :multiple="true"
    :taggable="false"
    @select="countrySelected($event)"
  ></multiselect>
</div>

</div>
</body>


Solution

  • Problem 1: you can keep the selected states in a separate variable as I keep it in selectedStates.

    Problem 2-3: You need to initialize your variable as seen in the demo below.

    Problem 4: Dynamic value will work for selectedStates[index]

    var app = new Vue({
      el: "#app",
      components: {
        Multiselect: window.VueMultiselect.default
      },
      data() {
        return {
          addMoreOptionsList: [],
          dynamicAddedOptionsHashMap: {},
          value: [],
          selectedStates: [],
          options: [{
              country: "America",
              states: ["CA", "MA"],
              id: "111"
            },
            {
              country: "India",
              states: ["KA", "MH"],
              id: "22222"
            },
    
            {
              country: "West Indies",
              states: ["West Indies1", "West Indies2"],
              id: "3333"
            }
          ]
        };
      },
      methods: {
        addMoreItems() {
          this.addMoreOptionsList.push("1 more added");
          this.selectedStates.push({
            id: null,
            values: []
          })
        },
        removeAll() {
          this.addMoreOptionsList = [];
          this.dynamicAddedOptionsHashMap = {};
          this.value = [];
          this.selectedStates = [];
        },
    
        getOptions(id) {
          const option = this.options.find((item) => item.id == id);
          console.log(option)
          if (option) return option.states;
          return []
        },
        selectTheState(index) {
          console.log(this.selectedStates);
          this.selectedStates[index].id = this.value[index].id
    
        }
      }
    });
    body {
      font-family: 'Arial'
    }
    
    .dropdown-item {
      display: flex;
      justify-content: space-between;
      margin-left: 20px;
      margin-top: 20px;
    }
    <!DOCTYPE HTML>
    <html>
    
    <head>
      <title>Timeline</title>
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      <script src="https://unpkg.com/vue-multiselect@2.1.0"></script>
      <link rel="stylesheet" href="https://unpkg.com/vue-multiselect@2.1.0/dist/vue-multiselect.min.css">
      <script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
    </head>
    
    <body>
      <div id="app">
    
        <div style="display: flex; margin-bottom: 20px; text-align: end; justify-content: flex-end;"><button style="margin-right:20px;" @click="removeAll()">X</button><button @click="addMoreItems()">+</button></div>
    
        <div class="dropdown-item" v-for="(item,index) in addMoreOptionsList">
          <multiselect v-model="value[index]" placeholder="Country?" label="country" :options="options" :multiple="false" :taggable="false"></multiselect>
    
    
          <multiselect style="margin-left:20px;" v-if="value[index]" v-model="selectedStates[index].values" placeholder="States?" :options="getOptions(value[index].id)" :multiple="true" :taggable="false" @select="selectTheState(index)"></multiselect>
        </div>
    
      </div>
    </body>