How do I preselect a vue-multiselect option when options is an array of objects?
Asked Answered
H

4

9

I want to pre-select a particular value in a select drop-down generated by vue-multiselect.
I can get this to work fine if I have a simple array of strings like the following:

['Test 1', 'Test 2', 'Test 3']

However, when I use an array of objects, I can't get this to work. For example, if I have the following:

<v-multiselect :options="[{id: 1, name: 'Test 1'}, {id: 2, name: 'Test 2'}, {id: 3, name: 'Test 3'}]"
               label="name"
               track-by="id"
               v-model="test">
</v-multiselect>

No matter what I set the test data property that v-model is connected to, it won't preselect the value. I've tried 1, 2, 3, '1', '2' and '3' for test when track-by is id and 'Test 1', etc. when track-by is name but nothing seems to work.

What am I doing wrong here? I looked at the docs at https://vue-multiselect.js.org/#sub-single-select-object, but they don't seem to provide an example when you want to preset a value for an array of objects for the options. Googling has also not returned what I'm looking for.

On a related topic, once I get this working, what would I have to change to select multiple values for when I set the component to multiple? Thank you.

Harber answered 20/2, 2019 at 20:21 Comment(0)
S
3

track-by usage

The docs indicate that track-by is "Used to compare objects. Only use if options are objects."

That is, it specifies the object key to use when comparing the object values in options. The docs should actually state that track-by is required when the options are objects because <vue-multiselect> uses track-by to determine which options in the dropdown are selected and to properly remove a selected option from a multiselect.

Without track-by, you'd see two buggy behaviors for object-options: (1) the user would be able to re-select already selected options, and (2) attempting to remove selected options would instead cause all options to be re-inserted.

Setting initial values

<vue-multiselect> doesn't support automatically translating a value array, but you could easily do that from the parent component.

  1. Create a local data property to specify track-by and initial multiselect values (e.g., named trackBy and initialValues, respectively):

    export default {
      data() {
        return {
          //...
          trackBy: 'id',
          initialValues: [2, 5],
        }
      }
    }
    
  2. Bind <vue-multiselect>.track-by to this.trackBy and <vue-multiselect>.v-model to this.value:

    <vue-multiselect :track-by="trackBy" v-model="value">
    
  3. Create a watcher on this.initialValues that maps those values into an object array based on this.trackBy, setting this.value to the result:

    export default {
      watch: {
        initialValues: {
          immediate: true,
          handler(values) {
            this.value = this.options.filter(x => values.includes(x[this.trackBy]));
          }
        }
      }
    }
    

Vue.component('v-multiselect', window.VueMultiselect.default);

new Vue({
  el: '#app',
  data () {
    return {
      trackBy: 'id',
      initialValues: [5,2],
      value: null,
      options: [
        { id: 1, name: 'Vue.js', language: 'JavaScript' },
        { id: 2, name: 'Rails', language: 'Ruby' },
        { id: 3, name: 'Sinatra', language: 'Ruby' },
        { id: 4, name: 'Laravel', language: 'PHP' },
        { id: 5, name: 'Phoenix', language: 'Elixir' }
      ]
    }
  },
  watch: {
    initialValues: {
      immediate: true,
      handler(values) {
        this.value = this.options.filter(x => values.includes(x[this.trackBy]));
      }
    }
  }
})
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
<script src="https://unpkg.com/[email protected]"></script>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/vue-multiselect.min.css">

<div id="app">
  <v-multiselect :track-by="trackBy"
                 :options="options"
                 v-model="value"
                 label="name"
                 multiple>
  </v-multiselect>
  <pre>{{ value }}</pre>
</div>
Sandeesandeep answered 21/2, 2019 at 8:3 Comment(1)
Thank you for explaining all of that. I get it, and I'm going to have to implement something like that, but honestly, it feels like a poor-man's solution. vue-multiselect should automatically handle this for you when you specify track-id.Harber
B
1

Looks like a bug. The workaround is to use an actual reference to the object

Vue.component('v-multiselect', window.VueMultiselect.default);
let testOptions=[{id: 1, name: 'Test 1'}, {id: 2, name: 'Test 2'}, {id: 3, name: 'Test 3'}]
new Vue({
  el: '#app',
  data: function () {
    return {
      test: testOptions[1], // <- use an object ref here!
      testOptions
    };
  }
});
Bulk answered 20/2, 2019 at 20:39 Comment(5)
Thanks for the reply, Steven. I've tried setting all of the following for test in my returned data object, and none of them work: 1, '1', [1], ['1'], { id: 1 }, { id: '1' }. Any other ideas? Thank you.Harber
Doesn't seem to make a difference. I set :options="testOptions" in the component and then set the following property in the data object: [{id: 1, name: 'Test 1'}, {id: 2, name: 'Test 2'}, {id: 3, name: 'Test 3'}]. Tried setting test to all the various possibilities again, but nothing worked. Any other ideas?Harber
Here ya go: codepen.io/HartleySan/pen/NomLqN?editors=1111. The commented-in code doesn't work, but if you switch that out with the commented out HTML and JS, then it pre-selects the Test 1 value. Not a clue.Harber
Steven, you're right, that does work. Not a great workaround though for two reasons: 1) I'm not going to readily have the selected object handy. Usually I'll have the ID, which I wanted to select the object from; and 2) If you do that, you don't even need the track-by attribute, in which case, what is that attribute for? Is it buggy? Maybe I'm misunderstanding something, but it seems like the library is buggy. If you set track-by="id", then I would think that you should be able to set test: 1 and be good to go. I wonder if I should submit a bug report on this.Harber
Its surely a bug. I started using vuetify after dealing with this kind of stuff...Bulk
A
0

The easiest way I found out is sending the whole object from BE, so it gets pre-selected. If you send the same object from BE will get pre-selected. But I don't know if your options are hard coded on FE or they are coming from a database or something. I had the same issue but my values were coming from my database, so it was easy to reproduce the object

Aftershock answered 15/3, 2021 at 15:32 Comment(0)
L
0

In your question just :object="true" is missing actually they didn't know that it is of type string or object when we pass this it knows yes it is object and i need label="name" from v-model="test" and picks it and shows it as a preselected

Lamothe answered 3/8, 2022 at 19:46 Comment(2)
I had a same issue and i fixed it in this wayLamothe
You are aware that you can edit your posts for adding information, aren't you? You could take the opportunity to try more along How to Answer.Aesop

© 2022 - 2024 — McMap. All rights reserved.