From b5af198f0d5b0f2b3ddb31ea12f700f3e0616271 Mon Sep 17 00:00:00 2001 From: Igor Minar Date: Thu, 7 Nov 2013 16:18:06 -0800 Subject: fix($compile): don't leak isolate scope state when replaced directive is used multiple times When an isolate scope directive is also a "replace" directive and at the root of its template it has other directives, we need to keep track remember to use isolate scope when linking these. This commit fixes the leakage of this state when this directive is used again later inside or outside of the isolate directive template. --- src/ng/compile.js | 13 +++++++++++-- test/ng/compileSpec.js | 39 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/ng/compile.js b/src/ng/compile.js index 5fefdaaa..7513fc7e 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -1303,13 +1303,17 @@ function $CompileProvider($provide) { if (pre) { if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd); pre.require = directive.require; - if (newIsolateScopeDirective === directive || directive.$$isolateScope) pre.isolateScope = true; + if (newIsolateScopeDirective === directive || directive.$$isolateScope) { + pre = cloneAndAnnotateFn(pre, {isolateScope: true}); + } preLinkFns.push(pre); } if (post) { if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd); post.require = directive.require; - if (newIsolateScopeDirective === directive || directive.$$isolateScope) post.isolateScope = true; + if (newIsolateScopeDirective === directive || directive.$$isolateScope) { + post = cloneAndAnnotateFn(post, {isolateScope: true}); + } postLinkFns.push(post); } } @@ -1830,6 +1834,11 @@ function $CompileProvider($provide) { elementsToRemove[0] = newNode; elementsToRemove.length = 1; } + + + function cloneAndAnnotateFn(fn, annotation) { + return extend(function() { return fn.apply(null, arguments); }, fn, annotation); + } }]; } diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index 356b1796..a61d50f2 100755 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -2504,7 +2504,7 @@ describe('$compile', function() { }); - it('should share isolate scope with replaced directives', function() { + it('should share isolate scope with replaced directives (template)', function() { var normalScope; var isolateScope; @@ -2540,7 +2540,7 @@ describe('$compile', function() { }); - it('should share isolate scope with replaced directives', function() { + it('should share isolate scope with replaced directives (templateUrl)', function() { var normalScope; var isolateScope; @@ -2577,6 +2577,41 @@ describe('$compile', function() { }); + it('should not get confused about where to use isolate scope when a replaced directive is used multiple times', + function() { + + module(function() { + directive('isolate', function() { + return { + replace: true, + scope: {}, + template: '' + }; + }); + directive('scopeTester', function(log) { + return { + link: function($scope, $element) { + log($element.attr('scope-tester') + '=' + ($scope.$root === $scope ? 'non-isolate' : 'isolate')); + } + } + }); + }); + + inject(function($compile, $rootScope, log) { + element = $compile('
' + + '
' + + '' + + '
')($rootScope); + + $rootScope.$digest(); + expect(log).toEqual('inside=isolate; ' + + 'outside replaced=non-isolate; ' + // outside + 'outside replaced=isolate; ' + // replaced + 'sibling=non-isolate') + }); + }); + + it('should require controller of a non-isolate directive from an isolate directive on the ' + 'same element', function() { var NonIsolateController = function() {}; -- cgit v1.2.3