From b0972a2e75909e41dbac6e4413ada7df2d51df3a Mon Sep 17 00:00:00 2001 From: Tobias Bosch Date: Tue, 26 Nov 2013 19:55:02 -0800 Subject: fix($compile): update cloned elements if the template arrives after the cloning If an element has a directive whose content is loaded using `templateUrl`, and the element is cloned using a linking function before the template arrives, the clone needs to be updated as well. This also updates `ngIf` and `ngRepeat` to keep the connection to the clone of a tranclude function, so that they know about the changes a directive with `templateUrl` does to the element in the future. Fixes to #4930. --- test/ng/compileSpec.js | 53 +++++++++++++++++++++++++++++++++++++++ test/ng/directive/ngIfSpec.js | 27 +++++++++++++++++++- test/ng/directive/ngRepeatSpec.js | 24 +++++++++++++++++- 3 files changed, 102 insertions(+), 2 deletions(-) (limited to 'test/ng') diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index c017bfa6..f2fa4ef6 100755 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -969,6 +969,32 @@ describe('$compile', function() { }); }); + it('should resolve widgets after cloning in append mode without $templateCache', function() { + module(function($exceptionHandlerProvider) { + $exceptionHandlerProvider.mode('log'); + }); + inject(function($compile, $templateCache, $rootScope, $httpBackend, $browser, + $exceptionHandler) { + $httpBackend.expect('GET', 'cau.html').respond('{{name}}'); + $rootScope.name = 'Elvis'; + var template = $compile('
'); + var e1; + var e2; + + e1 = template($rootScope.$new(), noop); // clone + expect(e1.text()).toEqual(''); + + $httpBackend.flush(); + + e2 = template($rootScope.$new(), noop); // clone + $rootScope.$digest(); + expect(e1.text()).toEqual('Elvis'); + expect(e2.text()).toEqual('Elvis'); + + dealoc(e1); + dealoc(e2); + }); + }); it('should resolve widgets after cloning in inline mode', function() { module(function($exceptionHandlerProvider) { @@ -1010,6 +1036,33 @@ describe('$compile', function() { }); }); + it('should resolve widgets after cloning in inline mode without $templateCache', function() { + module(function($exceptionHandlerProvider) { + $exceptionHandlerProvider.mode('log'); + }); + inject(function($compile, $templateCache, $rootScope, $httpBackend, $browser, + $exceptionHandler) { + $httpBackend.expect('GET', 'cau.html').respond('{{name}}'); + $rootScope.name = 'Elvis'; + var template = $compile(''); + var e1; + var e2; + + e1 = template($rootScope.$new(), noop); // clone + expect(e1.text()).toEqual(''); + + $httpBackend.flush(); + + e2 = template($rootScope.$new(), noop); // clone + $rootScope.$digest(); + expect(e1.text()).toEqual('Elvis'); + expect(e2.text()).toEqual('Elvis'); + + dealoc(e1); + dealoc(e2); + }); + }); + it('should be implicitly terminal and not compile placeholder content in append', inject( function($compile, $templateCache, $rootScope, log) { diff --git a/test/ng/directive/ngIfSpec.js b/test/ng/directive/ngIfSpec.js index 427bfd59..db923150 100755 --- a/test/ng/directive/ngIfSpec.js +++ b/test/ng/directive/ngIfSpec.js @@ -1,8 +1,11 @@ 'use strict'; describe('ngIf', function () { - var $scope, $compile, element; + var $scope, $compile, element, $compileProvider; + beforeEach(module(function(_$compileProvider_) { + $compileProvider = _$compileProvider_; + })); beforeEach(inject(function ($rootScope, _$compile_) { $scope = $rootScope.$new(); $compile = _$compile_; @@ -146,6 +149,28 @@ describe('ngIf', function () { expect(element.children()[0].className).toContain('my-class'); }); + it('should work when combined with an ASYNC template that loads after the first digest', inject(function($httpBackend, $compile, $rootScope) { + $compileProvider.directive('test', function() { + return { + templateUrl: 'test.html' + }; + }); + $httpBackend.whenGET('test.html').respond('hello'); + element.append(''); + $compile(element)($rootScope); + $rootScope.show = true; + $rootScope.$apply(); + expect(element.text()).toBe(''); + + $httpBackend.flush(); + expect(element.text()).toBe('hello'); + + $rootScope.show = false; + $rootScope.$apply(); + // Note: there are still comments in element! + expect(element.children().length).toBe(0); + expect(element.text()).toBe(''); + })); }); describe('ngIf and transcludes', function() { diff --git a/test/ng/directive/ngRepeatSpec.js b/test/ng/directive/ngRepeatSpec.js index 6584f31a..bdc0b8f5 100644 --- a/test/ng/directive/ngRepeatSpec.js +++ b/test/ng/directive/ngRepeatSpec.js @@ -749,8 +749,30 @@ describe('ngRepeat', function() { expect(element.text()).toBe('123'); })); } - }); + it('should work when combined with an ASYNC template that loads after the first digest', inject(function($httpBackend, $compile, $rootScope) { + $compileProvider.directive('test', function() { + return { + templateUrl: 'test.html' + }; + }); + $httpBackend.whenGET('test.html').respond('hello'); + element = jqLite('