Skip to content

Commit f425223

Browse files
committed
fix(select): respect tracking expression when shallow watching arrays of objects in ngOptions
ngOptions does not use the tracking expression when shallow watching array elements passed in to ngOptions. This is a problem if the elements passed in to ngOptions are generated on the fly and while the array elements identical in value, they are different instances; this leads to infinite digest loops. This change attempts to rectify the situation by shallow watching an array of trackFn(values) rather than the array of values themselves. Closes angular#9464
1 parent 613d0a3 commit f425223

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

src/ng/directive/select.js

+17-1
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,23 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
414414

415415
ctrl.$render = render;
416416

417-
scope.$watchCollection(valuesFn, scheduleRendering);
417+
if (trackFn) {
418+
scope.$watchCollection(function() {
419+
var locals = {},
420+
values = valuesFn(scope);
421+
if (values) {
422+
var trackers = new Array(values.length);
423+
for (var i = 0, ii = values.length; i < ii; i++) {
424+
trackers[i] = trackFn(scope, locals);
425+
}
426+
427+
return trackers;
428+
}
429+
}, scheduleRendering);
430+
} else {
431+
scope.$watchCollection(valuesFn, scheduleRendering);
432+
}
433+
418434
scope.$watchCollection(function () {
419435
var locals = {},
420436
values = valuesFn(scope);

test/ng/directive/selectSpec.js

+23
Original file line numberDiff line numberDiff line change
@@ -1162,6 +1162,29 @@ describe('select', function() {
11621162
expect(element.val()).toEqual('?');
11631163
expect(element.find('option').eq(0).attr('selected')).toEqual('selected');
11641164
});
1165+
1166+
it('should respect trackexpr when working with arrays of objects', function() {
1167+
var elementCount = 5;
1168+
1169+
createSelect({
1170+
'ng-model':'selected',
1171+
'ng-options':'v as v.label for v in makeValues() track by v.code'
1172+
});
1173+
1174+
scope.$apply(function() {
1175+
scope.makeValues = function() {
1176+
var values = [];
1177+
for (var i = 0; i < elementCount; i++) {
1178+
values.push({label: 'Value = ' + i, code: i});
1179+
}
1180+
1181+
return values;
1182+
};
1183+
scope.selected = {label: 'Value = 1', code: 1};
1184+
});
1185+
1186+
expect(element.find('option').length).toEqual(elementCount);
1187+
});
11651188
});
11661189

11671190

0 commit comments

Comments
 (0)