Vue-select: Select output value when options are an array of objects

Created on 20 Nov 2018  路  10Comments  路  Source: sagalbot/vue-select

Is it possible to add a prop to select the output value when options are an array of the objects.
Something like
<v-select multiple v-model="selected" output-value="name"></v-select>
Where options are
const options = [ { id: 1, name: "name1" }, { id: 2, name: "name2" } ]
v-model values if both selected should be:
[ "name1", "name2"]

If interested I can submit a PR with this feature

performance

Most helpful comment

@juanr2001 thanks for your answer but I think my comment wasn't very clear because we aren't talking about the same issue 馃槃
I agree with you that sometimes we need an array of strings and sometimes we need an array of objects.

If I use a native <select>, I would write something like that:

<select v-model="selected">
  <option v-for="option in options" :value="option.value">
    {{ option.label }}
  </option>
</select>

selected is the option value, because I want to display the label (eventually in different languages) but I only need to send the value to the API (which doesn't care about the label).

But currently this component provides something like that:

<select v-model="selected">
  <option v-for="option in options" :value="option">
    {{ option.label }}
  </option>
</select>

So selected is the whole option object.

This may be an issue when you want to initialise selected with a value from API (option.value), because you have to find the option object and can't use v-model anymore:

selectedOption() {
  return this.options.find(option => option.value === this.value);
}

All 10 comments

I started to use this component with object options ({value, label}) and it was very confusing because I expected the v-model to be the value of the option, not the option object.
So it makes my wrapper component (which also provides v-model ) more complicated 馃槥
Is it a bug or a choice?

@VictorCazanave I do not believe this is a bug.

There are cases where you need an object. There are cases where you need and array.

Example, you need a object when you have a website that supports more than 1 language.
You could have an api that expects a data as follows

  data = {
    status: 'a' // other statuses: 'b', 'c'
  }

Now, if user expects your website to be in Spanish and English you must have to be able to translated and send the data that your API is expecting. That's when you need an object, because you can set the object as follow

{
  label: 'This is A': // Spanish Este es A,
  value: a
}

It will not matter what the label is, you will always have a standard value that your API is expecting.

I hope this answers your question :)

NOTE: you can have access to the object when using v-bind:onChange="createAMethod"

{
  data () {
     return {val: ''}
  },
  methods: {
    createAMethod (val) {
      // returns the object and you can do whatever you want with the value the object returns.
      this.val = val.value
   }
  }
}

@juanr2001 thanks for your answer but I think my comment wasn't very clear because we aren't talking about the same issue 馃槃
I agree with you that sometimes we need an array of strings and sometimes we need an array of objects.

If I use a native <select>, I would write something like that:

<select v-model="selected">
  <option v-for="option in options" :value="option.value">
    {{ option.label }}
  </option>
</select>

selected is the option value, because I want to display the label (eventually in different languages) but I only need to send the value to the API (which doesn't care about the label).

But currently this component provides something like that:

<select v-model="selected">
  <option v-for="option in options" :value="option">
    {{ option.label }}
  </option>
</select>

So selected is the whole option object.

This may be an issue when you want to initialise selected with a value from API (option.value), because you have to find the option object and can't use v-model anymore:

selectedOption() {
  return this.options.find(option => option.value === this.value);
}

I will chime in and say, like @VictorCazanave, I was also surprised to find the value synced to v-model was an object, and not the value part of my object. I would really like this to behave more like a traditional <select> as has been proposed.

I would propose that a new prop be added, maybe something like value-prop="id". When absent, the current behavior would be retained, but if present it should use the prop matching that key name as the value. (and use something like the proposed selectedOption() to find the value)

I'll even spend some time tonight to create a PR based on that idea.

When I started digging into the code, the index prop looks like what I was looking for, but when I added it my app became really slow and unresponsive when attempting to interact with <vue-select>, I'm digging in now to see if I can understand why.

Looks like a big problem is the complexity of this code:

It's actually looping every item (it doesn't stop when it finds a match) and doing a JSON.stringify on both the option object and the value to compare them. I have just shy of 500 options and this is a huge bottleneck in my case. I started off by passing some moderately large objects as the options (was thinking I'd avoid making copies just for these options) but trimming them down to just the properties I needed made a big difference, but it's still pretty bad.

I'll try to focus on making findOptionByIndexValue() perform better, which should be a good starting point.

is this corrected?
Do we have a prop the retrieves only the value?

Related to #770. @joelpro2 currently the index prop does what you're looking for.

The API for this is much more robust in v3.0. index has been removed, and a reduce function has been added.

https://vue-select.org/guide/upgrading.html#index-prop-replaced-with-reduce

Was this page helpful?
0 / 5 - 0 ratings