Skip to content
Permalink
Browse files

fix(ngOptions): prevent infinite digest if track by expression is stable

Closes #9464
  • Loading branch information...
petebacondarwin committed Jan 11, 2015
1 parent b4bdec3 commit fc21db8a15545fad53124fc941b3c911a8d57067
Showing with 28 additions and 5 deletions.
  1. +11 −5 src/ng/directive/ngOptions.js
  2. +17 −0 test/ng/directive/ngOptionsSpec.js
@@ -227,8 +227,14 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
var valueFn = $parse(match[2] ? match[1] : valueName);
var selectAsFn = selectAs && $parse(selectAs);
var viewValueFn = selectAsFn || valueFn;
var trackByFn = trackBy ? $parse(trackBy) :
function getHashOfValue(value) { return hashKey(value); };
var trackByFn = trackBy && $parse(trackBy);

// Get the value by which we are going to track the option
// if we have a trackFn then use that (passing scope and locals)
// otherwise just hash the given viewValue
var getTrackByValue = trackBy ?
function(viewValue, locals) { return trackByFn(scope, locals); } :
function getHashOfValue(viewValue) { return hashKey(viewValue); };
var displayFn = $parse(match[2] || match[1]);
var groupByFn = $parse(match[3] || '');
var valuesFn = $parse(match[7]);
@@ -263,7 +269,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
Object.keys(values).forEach(function getWatchable(key) {
var locals = getLocals(values[key], key);
var label = displayFn(scope, locals);
var selectValue = viewValueFn(scope, locals);
var selectValue = getTrackByValue(values[key], locals);
watchedArray.push(selectValue);
watchedArray.push(label);
});
@@ -288,7 +294,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
var value = optionValues[key];
var locals = getLocals(value, key);
var viewValue = viewValueFn(scope, locals);
var selectValue = trackByFn(viewValue, locals);
var selectValue = getTrackByValue(viewValue, locals);
var label = displayFn(scope, locals);
var group = groupByFn(scope, locals);
var optionItem = new Option(selectValue, viewValue, label, group);
@@ -301,7 +307,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
items: optionItems,
selectValueMap: selectValueMap,
getOptionFromViewValue: function(value) {
return selectValueMap[trackByFn(value, getLocals(value))];
return selectValueMap[getTrackByValue(value, getLocals(value))];
}
};
}
@@ -706,6 +706,23 @@ describe('ngOptions', function() {
browserTrigger(element, 'change');
expect(scope.selected).toEqual([scope.obj['1'], scope.obj['2']]);
});

it('should prevent infinite digest if track by expression is stable', function() {
scope.makeOptions = function() {
var options = [];
for (var i = 0; i < 5; i++) {
options.push({ label: 'Value = ' + i, value: i });
}
return options;
};
scope.selected = { label: 'Value = 1', value: 1 };
expect(function() {
createSelect({
'ng-model': 'selected',
'ng-options': 'item.label for item in makeOptions() track by item.value'
});
}).not.toThrow();
});
});


0 comments on commit fc21db8

Please sign in to comment.
You can’t perform that action at this time.