Vue-multiselect: Track by is not used everywhere

Created on 15 May 2018  路  6Comments  路  Source: shentao/vue-multiselect

Hi,

We store IDs in database and thus we provide the select component the selected ID as the model.

Similarly, when form gets submitted, we expect the selected ID to be sent along with the form data.

Currently, the value property only accepts a full object. It does not take into account the track-by property which tells how we identify our objects.

I saw another issue related to the preselected item(s). But I want to also add that the resulting value sent with the form should also be the tracked property of the item (not the whole item).

invalid

Most helpful comment

If it helps somebody: @alex3683 's workaround for multi select:

<multiselect multiple
   :value="actualSelection.map(selection => options.find( _ => _.id === selection))"
   @input="actualSelection = $event && $event.map(_ => _.id)"
   :options="options"/>

All 6 comments

For instance, given options = [ { 'id': 1, 'label': 'John' }, { 'id': 2, 'label': 'Jane' } ], track-by="id" and label="label"

I would expect that:

  • value="1" selects the option 'John'
  • the target v-model property contains '2' when I select 'Jane'
  • the form gets sent with the value '2' for the corresponding named select input

i thought the same thing, though that probably cant be done for backwards compatibility reasons a new prob would be required.

My not quite so nice but it works workaround is at
https://github.com/shentao/vue-multiselect/issues/720

As a workaround I currently use a computed property split into getter and setter:

{
   data: () => ({
      actualSelection: -1,
      options: [ { 'id': 1, 'label': 'John' }, { 'id': 2, 'label': 'Jane' } ]
   }),
   computed: {
      wrappedSelection: {
         get() {
            if( this.actualSelection === -1 ) {
               return null;
            }
            return this.options.find( _ => _.id === this.actualSelection );
         },
         set( value ) {
            this.actualSelection = value != null ? value.id : -1;
         }
      }
   }
}

Then bind the multiselect component to the wrappedSelection instead of the actualSelection.
(I just wrote this down here as example without testing, so be careful ;-))

EDIT: Just wanted to point out that, although there is a workaround, it would be great to have a builtin way to achieve this. I use object-options, persisted by their ids everywhere in my applications.

EDIT2: Even shorter workaround:

<multiselect
   :value="options.find( _ => _.id === actualSelection )"
   @input="actualSelection = $event && $event.id"
   :options="options"/>

No need to change the model here.

Fine if you have a few selects in your whole app. But that is quite a lot of code to write again and again when select2 is just compatible with HTML forms from start.

Will try latest workaround to check if that makes it acceptable though.

If it helps somebody: @alex3683 's workaround for multi select:

<multiselect multiple
   :value="actualSelection.map(selection => options.find( _ => _.id === selection))"
   @input="actualSelection = $event && $event.map(_ => _.id)"
   :options="options"/>

Using a computed property with a getter/setter (that @alex3683 mentioned) is the recommended approach.

This can鈥檛 be done otherwise for the reasons you mentioned (preselecting, async options etc). The decision to do it this is that it鈥檚 easier to extract the id from the whole object than to dynamically recreate objects based on just the id where for example other data needed for displaying might not be available.
I imagine it would result in even more issues being created... :(

Was this page helpful?
0 / 5 - 0 ratings

Related issues

katranci picture katranci  路  3Comments

MaxHalford picture MaxHalford  路  4Comments

wujekbogdan picture wujekbogdan  路  4Comments

volkanciloglu picture volkanciloglu  路  3Comments

hskrishna29 picture hskrishna29  路  3Comments