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

Commit f210669

Browse files
vojtajinaIgorMinar
authored andcommitted
fix($compile): properly clone attr.$observers in ng-repeat
The `attr` object was only shallow copied which caused all observers to be shared. Fixing similar issue in ng-* boolean attributes as well as ng-src and ng-href.
1 parent 4557881 commit f210669

File tree

3 files changed

+40
-2
lines changed

3 files changed

+40
-2
lines changed

src/ng/compiler.js

+1
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,7 @@ function $CompileProvider($provide) {
611611
} else {
612612
attrs = shallowCopy(templateAttrs);
613613
attrs.$element = jqLite(linkNode);
614+
attrs.$observers = {};
614615
}
615616
element = attrs.$element;
616617

src/ng/directive/booleanAttrDirs.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -283,9 +283,10 @@ forEach(BOOLEAN_ATTR, function(propName, attrName) {
283283
var normalized = directiveNormalize('ng-' + attrName);
284284
ngAttributeAliasDirectives[normalized] = function() {
285285
return {
286+
priority: 100,
286287
compile: function(tpl, attr) {
287-
attr.$observers[attrName] = [];
288288
return function(scope, element, attr) {
289+
attr.$observers[attrName] = [];
289290
scope.$watch(attr[normalized], function(value) {
290291
attr.$set(attrName, value);
291292
});
@@ -301,9 +302,10 @@ forEach(['src', 'href'], function(attrName) {
301302
var normalized = directiveNormalize('ng-' + attrName);
302303
ngAttributeAliasDirectives[normalized] = function() {
303304
return {
305+
priority: 100,
304306
compile: function(tpl, attr) {
305-
attr.$observers[attrName] = [];
306307
return function(scope, element, attr) {
308+
attr.$observers[attrName] = [];
307309
attr.$observe(normalized, function(value) {
308310
attr.$set(attrName, value);
309311
});

test/ng/compilerSpec.js

+35
Original file line numberDiff line numberDiff line change
@@ -1374,6 +1374,41 @@ describe('$compile', function() {
13741374
});
13751375

13761376

1377+
it('should properly $observe inside ng-repeat', function() {
1378+
var spies = [];
1379+
1380+
module(function($compileProvider) {
1381+
$compileProvider.directive('observer', function() {
1382+
return function(scope, elm, attr) {
1383+
spies.push(jasmine.createSpy('observer ' + spies.length));
1384+
attr.$observe('some', spies[spies.length - 1]);
1385+
};
1386+
});
1387+
});
1388+
1389+
inject(function($compile, $rootScope) {
1390+
element = $compile('<div><div ng-repeat="i in items">'+
1391+
'<span some="id_{{i.id}}" observer></span>'+
1392+
'</div></div>')($rootScope);
1393+
1394+
$rootScope.$apply(function() {
1395+
$rootScope.items = [{id: 1}, {id: 2}];
1396+
});
1397+
1398+
expect(spies[0]).toHaveBeenCalledOnceWith('id_1');
1399+
expect(spies[1]).toHaveBeenCalledOnceWith('id_2');
1400+
spies[0].reset();
1401+
spies[1].reset();
1402+
1403+
$rootScope.$apply(function() {
1404+
$rootScope.items[0].id = 5;
1405+
});
1406+
1407+
expect(spies[0]).toHaveBeenCalledOnceWith('id_5');
1408+
});
1409+
});
1410+
1411+
13771412
describe('$set', function() {
13781413
var attr;
13791414
beforeEach(function(){

0 commit comments

Comments
 (0)