Vue: <select> bound with array performs incorrectly after splice()

Created on 30 Sep 2016  ·  6Comments  ·  Source: vuejs/vue

Consider the following code:

<div id="demo">
  <select v-model="selected" number>
    <option v-for="opt in options" :value="$index" number>{{opt}}</option>
  </select>
</div>

In <select>, each option value is bound with $index. If we perform splice() on options, like, options.splice(0,1), $index does not correctly sync with options.

For example, let options=['a','b'] and the rendered HTML looks like (but not really):

<div id="demo">
  <select selectedIndex="0">
    <option value="0">a</option>
    <option value="1">b</option>
  </select>
</div>

After options.splice(0,1), then options=['b'], but the rendered HTML becomes:

<div id="demo">
  <select selectedIndex="0">
    <option value="1">b</option>
  </select>
</div>

The value of 'b' option does not become 1, which should be 0 because of $index. This may not be a bug, but this is kind of odd.

Below is the live demo of this issue:
https://jsfiddle.net/peteranny/trwp98g9/4/

bug

Most helpful comment

Tested on 2.0 and it worked as expected: https://jsfiddle.net/dycmgzcm/
So I'm marking this as a bug of 1.x

All 6 comments

Just add a selected attribute in your template selected="{{$index == selected}}"

I update the demo here https://jsfiddle.net/trwp98g9/5/

@peteranny Can you clarify what was the expected behavior?

After options.splice(0,1), then options=['b'], but the rendered HTML becomes:
<option value="1">b</option>

I'm not getting the same result as you provided from here:
Before clicking remove:
before

After clicking:
after

The value of 'b' option does not become 1, which should be 0 because of $index

So what exactly should it become? The value of 'b' was 1 before click, and became 0 after click.

@fnlctrl Um, thank you for your testing. I think I've asked the wrong question.
According to your testing, the value of 'b' did become 0 after click.

My true question is: now that the value of 'b' was 0, why was <select> not selecting 'b' anyway?
As seen in your image, <select> did not select any option at all, while <select> is ought to select the option with the value 0.
(And that is why I misguessed that the value of 'b' didn't change.)

@peteranny It may be a bug because selected remained 0 while the options changed, and the dom is supposed to reflect this change, but I'm not sure..

For now, you can try adding selected prop as @defcc suggested, (note that mustache binding for props/attrs is deprecated in 2.0, so please use :selected="$index == selected" instead)
Or you can add a track-by prop to <options>, which probably made vue think it's safe to update the selected value in dom. https://jsfiddle.net/74ncq90w/

Tested on 2.0 and it worked as expected: https://jsfiddle.net/dycmgzcm/
So I'm marking this as a bug of 1.x

Closing 1.x issues as 1.x is now end of life and will only receive critical security patches.

Was this page helpful?
0 / 5 - 0 ratings