Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

ngOptions with "track by" triggers ngChange when ngModel did not change #11936

Closed
@ryanhart2

Description

@ryanhart2

Overview of the Issue

<select
  ng-options="option.id for option in vm.options track by option.id"
  ng-model="vm.model"
  ng-change="vm.update()">
</select>

vm.options is an array of objects with a unique id property. When the <select> is first created, ngChange is triggered if ngModel is an object that does not have the same reference as any of the objects in vm.options even though it may be identical in value to one of them. As there has not been a change to the ngModel value, it is not expected that ngChange is triggered.

Motivation for or Use Case

There are two <select> elements for the user to select the make and model of a car. The options available for <select>model are dependent on the selected value in <select>make. Therefore, when the selected value in <select>make changes, the selected value in <select>model should be cleared. This works with no issues. However, when navigating away from and back to the <select> elements, the <select>model is cleared even though the value of <select>make did not change. This is not expected.

Angular Version(s)
This issue does not occur with version 1.3.15 through to 1.4.0-beta.6
This issue does occur with versions 1.4.0-rc.0 through to at least 1.4.0-rc.2

Browsers and Operating System
Chrome 43.0.2357.65 m, Firefox 38.0.1, IE 11.0.9600.17801
Windows 8.1 Pro

Reproduce the Error
http://plnkr.co/edit/xe4HPLZVEHqO7XYW1kGX?p=preview

Related Issues
#11448
#11447

Suggest a Fix
The issue seems to result from this commit: 171b9f7

In the code below, when previousValue !== nextValue is true, ngModelCtrl.$setViewValue(nextValue) is invoked, even though ngOptions.trackBy is true and !equals(previousValue, nextValue) is false.

// Check to see if the value has changed due to the update to the options
if (!ngModelCtrl.$isEmpty(previousValue)) {
  var nextValue = selectCtrl.readValue();
  if (ngOptions.trackBy && !equals(previousValue, nextValue) ||
        previousValue !== nextValue) {
    ngModelCtrl.$setViewValue(nextValue);
    ngModelCtrl.$render();
  }
}

The code to compare previousValue and nextValue could be changed to:

if (ngOptions.trackBy ? !equals(previousValue, nextValue) : previousValue !== nextValue) {

This would result in a deep comparison when track by is used and a reference comparison when track by is not used.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions