Angular.js: Angular 1.6 incorrectly resets `<select>'s `ng-model` value

Created on 20 Jan 2017  ·  3Comments  ·  Source: angular/angular.js

Note: for support questions, please use one of these channels: https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#question. This repository's issues are reserved for feature requests and bug reports.

Do you want to request a feature or report a bug?
Bug

What is the current behavior?
Angular 1.6 resets <select>s ng-model value when <option>s list changes (see "Other information" section).
Angular 1.5 preserves it.

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://plnkr.co or similar (template: http://plnkr.co/edit/tpl:yBpEi4).
Angular 1.6: https://plnkr.co/edit/wHc4rzy7x9PAEqQLfVQT?p=preview
Angular 1.5.11: https://plnkr.co/edit/e0LVMEtGP2j4JxNf8lsp?p=preview

What is the expected behavior?
ng-model preserves it's value.

What is the motivation / use case for changing the behavior?
It's not correct.

Which versions of Angular, and which browser / OS are affected by this issue? Did this work in previous versions of Angular? Please also test with the latest stable and snapshot (https://code.angularjs.org/snapshot/) versions.
Angular 1.6.x is affected.
Angular 1.5.x is not.

Other information (e.g. stacktraces, related issues, suggestions how to fix)
The thing is Angular 1.6 tracks options by it's model and not by the optionss value.

In the snippets above options array contains 2 objects: [{val: "1"}, {val: "2"}].
ng-repeat iterates through them and uses val property as both option value and title.
vm.selected is used as select's ng-model value and is initially set to "2".

After pressing Change options button I replace options array with this one: [{val: "2"}, {val: "3"}] and Angular 1.6 resets vm.selected value but it shouldn't because option with value 2 is still in the list.

Angular 1.5 behaves correctly in this case and vm.selected value is preserved.

If vm.options contains primitive values bug doesn't appear (snippet).

forms low investigation regression bug

Most helpful comment

Looks like this was an intentional change in https://github.com/angular/angular.js/commit/47c15fbcc10f118170813021e8e605ffd263ad84: "- when an option that is currently selected, is removed or its value changes, the model is set to null." but this didn't take into account that this might be breaking, or that ngRepeat would take a digest to update the options. It's also easier to do in ngOptions because we control the creation / destruction of elements.
But scheduleRender() works, yay for @gkalpak ! I'll see if it breaks tests and prepare a PR.

All 3 comments

Seems like a valid issue and it breaks in 1.6.0-rc.0. Not sure why it didn't happen before, but the issue seems to be this:

  1. When the array changes, ngRepeat removes the previous <option> elements.
  2. This causes the <select> to get unselected and ngModel to be set to null.
  3. The new items are created and inserted by ngRepeat, but the modelValue is not 2 any more, so <select> has no way to associate it with the new <option value="2" ...>.

A work-around is to use track by to avoid destroying and recreating the <option> elements:

<option ng-repeat="option in options track by option.val" value="option.val">...

#

from a quick look, the following commits are candidates for having caused this (but it could be something else):

  • f02b707
  • 47c15fb
  • 2785ad7

#

Off the top of my head, I would start by replacing this line with scheduleRender() and see if it helps...

I am sure @Narretz will have some better insights :smiley:

A work-around is to use track by to avoid destroying and recreating the

Yes, found it out too but forgot to mention 😏

Looks like this was an intentional change in https://github.com/angular/angular.js/commit/47c15fbcc10f118170813021e8e605ffd263ad84: "- when an option that is currently selected, is removed or its value changes, the model is set to null." but this didn't take into account that this might be breaking, or that ngRepeat would take a digest to update the options. It's also easier to do in ngOptions because we control the creation / destruction of elements.
But scheduleRender() works, yay for @gkalpak ! I'll see if it breaks tests and prepare a PR.

Was this page helpful?
0 / 5 - 0 ratings