diff --git a/src/ng/directive/ngOptions.js b/src/ng/directive/ngOptions.js index 2498042579d6..38e9397f7eca 100644 --- a/src/ng/directive/ngOptions.js +++ b/src/ng/directive/ngOptions.js @@ -303,6 +303,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) { values = values || []; Object.keys(values).forEach(function getWatchable(key) { + if (key.charAt(0) === '$') return; var locals = getLocals(values[key], key); var selectValue = getTrackByValueFn(values[key], locals); watchedArray.push(selectValue); diff --git a/test/ng/directive/ngOptionsSpec.js b/test/ng/directive/ngOptionsSpec.js index 33cdfb00ce38..8d897b6bc606 100644 --- a/test/ng/directive/ngOptionsSpec.js +++ b/test/ng/directive/ngOptionsSpec.js @@ -448,6 +448,41 @@ describe('ngOptions', function() { }); + it('should not watch array properties that start with $ or $$', function() { + createSelect({ + 'ng-options': 'value as createLabel(value) for value in array', + 'ng-model': 'selected' + }); + scope.createLabel = jasmine.createSpy('createLabel').andCallFake(function(value) { return value; }); + scope.array = ['a', 'b', 'c']; + scope.array.$$private = 'do not watch'; + scope.array.$property = 'do not watch'; + scope.selected = 'b'; + scope.$digest(); + + expect(scope.createLabel).toHaveBeenCalledWith('a'); + expect(scope.createLabel).toHaveBeenCalledWith('b'); + expect(scope.createLabel).toHaveBeenCalledWith('c'); + expect(scope.createLabel).not.toHaveBeenCalledWith('do not watch'); + }); + + + it('should not watch object properties that start with $ or $$', function() { + createSelect({ + 'ng-options': 'key as createLabel(key) for (key, value) in object', + 'ng-model': 'selected' + }); + scope.createLabel = jasmine.createSpy('createLabel').andCallFake(function(value) { return value; }); + scope.object = {'regularProperty': 'visible', '$$private': 'invisible', '$property': 'invisible'}; + scope.selected = 'regularProperty'; + scope.$digest(); + + expect(scope.createLabel).toHaveBeenCalledWith('regularProperty'); + expect(scope.createLabel).not.toHaveBeenCalledWith('$$private'); + expect(scope.createLabel).not.toHaveBeenCalledWith('$property'); + }); + + it('should allow expressions over multiple lines', function() { scope.isNotFoo = function(item) { return item.name !== 'Foo';