From fc115bfd0d18017f4bcef1e39fb22d97a98f8ab1 Mon Sep 17 00:00:00 2001 From: Igor Minar Date: Thu, 25 Oct 2012 00:33:36 -0700 Subject: [PATCH] fix($compile): prevent double attr interpolation w/ templateUrl This fixes the issue that caused two attr interpolation observers to be registered for the same attribute as a result of isolate scope definition with attr (@) property for this attribute. Duplicate observers would then fight with each other updating the model. The issue occured only when this directive was used in a repeater because that's when we clone the template node which caused the two observers to point to two different sets of $attr instances. Closes #1166, #836 --- src/ng/compile.js | 2 +- test/ng/compileSpec.js | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/ng/compile.js b/src/ng/compile.js index 3fa4691ccbe4..ae926923069c 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -899,7 +899,7 @@ function $CompileProvider($provide) { origAsyncDirective = directives.shift(), // The fact that we have to copy and patch the directive seems wrong! derivedSyncDirective = extend({}, origAsyncDirective, { - controller: null, templateUrl: null, transclude: null + controller: null, templateUrl: null, transclude: null, scope: null }); $compileNode.html(''); diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index b5e4c4507504..75af01810e12 100644 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -1048,6 +1048,39 @@ describe('$compile', function() { expect($exceptionHandler.errors).toEqual([]); }); }); + + + it('should resume delayed compilation without duplicates when in a repeater', function() { + // this is a test for a regression + // scope creation, isolate watcher setup, controller instantiation, etc should happen + // only once even if we are dealing with delayed compilation of a node due to templateUrl + // and the template node is in a repeater + + var controllerSpy = jasmine.createSpy('controller'); + + module(function($compileProvider) { + $compileProvider.directive('delayed', valueFn({ + controller: controllerSpy, + templateUrl: 'delayed.html', + scope: { + title: '@' + } + })); + }); + + inject(function($templateCache, $compile, $rootScope) { + $rootScope.coolTitle = 'boom!'; + $templateCache.put('delayed.html', '
{{title}}
'); + element = $compile( + '
|
' + )($rootScope); + + $rootScope.$apply(); + + expect(controllerSpy.callCount).toBe(2); + expect(element.text()).toBe('boom!1|boom!2|'); + }); + }); });