');
+ });
});
- });
- inject(function(log, $rootScope, $compile, $templateCache) {
- $templateCache.put('trans.html', '
')($rootScope);
- $rootScope.$apply();
- expect(log).toEqual('pre(); post(unicorn!)');
- });
- });
- it('should copy the directive controller to all clones', function() {
- var transcludeCtrl, cloneCount = 2;
- module(function() {
- directive('transclude', valueFn({
- transclude: 'content',
- controller: function($transclude) {
- transcludeCtrl = this;
- },
- link: function(scope, el, attr, ctrl, $transclude) {
- var i;
- for (i = 0; i < cloneCount; i++) {
- $transclude(cloneAttach);
- }
+ it('should not pass transclusion into a templateUrl directive', function() {
- function cloneAttach(clone) {
- el.append(clone);
- }
- }
- }));
- });
- inject(function($compile) {
- element = $compile('
')($rootScope);
- var children = element.children(), i;
- expect(transcludeCtrl).toBeDefined();
+ module(function($compileProvider) {
- expect(element.data('$transcludeController')).toBe(transcludeCtrl);
- for (i = 0; i < cloneCount; i++) {
- expect(children.eq(i).data('$transcludeController')).toBeUndefined();
- }
- });
- });
+ $compileProvider.directive('transFoo', valueFn({
+ template: '
',
+ transclude: true
- it('should provide the $transclude controller local as 5th argument to the pre and post-link function', function() {
- var ctrlTransclude, preLinkTransclude, postLinkTransclude;
- module(function() {
- directive('transclude', valueFn({
- transclude: 'content',
- controller: function($transclude) {
- ctrlTransclude = $transclude;
- },
- compile: function() {
- return {
- pre: function(scope, el, attr, ctrl, $transclude) {
- preLinkTransclude = $transclude;
- },
- post: function(scope, el, attr, ctrl, $transclude) {
- postLinkTransclude = $transclude;
- }
- };
- }
- }));
- });
- inject(function($compile) {
- element = $compile('
')($rootScope);
- expect(ctrlTransclude).toBeDefined();
- expect(ctrlTransclude).toBe(preLinkTransclude);
- expect(ctrlTransclude).toBe(postLinkTransclude);
- });
- });
+ }));
+
+ $compileProvider.directive('noTransBar', valueFn({
+ templateUrl: 'noTransBar.html',
+ transclude: false
+
+ }));
+ });
+
+ inject(function($compile, $rootScope, $templateCache) {
+ $templateCache.put('noTransBar.html',
+ '
')($rootScope);
+ $rootScope.$apply();
+ }).toThrowMinErr('ngTransclude', 'orphan',
+ 'Illegal use of ngTransclude directive in the template! No parent directive that requires a transclusion found. Element:
');
+ });
+ });
+
+
+ it('should expose transcludeFn in compile fn even for templateUrl', function() {
+ module(function() {
+ directive('transInCompile', valueFn({
+ transclude: true,
+ // template: '
whatever
',
+ templateUrl: 'foo.html',
+ compile: function(_, __, transclude) {
+ return function(scope, element) {
+ transclude(scope, function(clone, scope) {
+ element.html('');
+ element.append(clone);
+ });
+ };
+ }
+ }));
+ });
- it('should allow an optional scope argument in $transclude', function() {
- var capturedChildCtrl;
- module(function() {
- directive('transclude', valueFn({
- transclude: 'content',
- link: function(scope, element, attr, ctrl, $transclude) {
- $transclude(scope, function(clone) {
- element.append(clone);
+ inject(function($compile, $rootScope, $templateCache) {
+ $templateCache.put('foo.html', '
whatever
');
+
+ compile('
transcluded content
');
+ $rootScope.$apply();
+
+ expect(trim(element.text())).toBe('transcluded content');
+ });
+ });
+
+
+ it('should make the result of a transclusion available to the parent directive in post-linking phase' +
+ '(template)', function() {
+ module(function() {
+ directive('trans', function(log) {
+ return {
+ transclude: true,
+ template: '
',
+ link: {
+ pre: function($scope, $element) {
+ log('pre(' + $element.text() + ')');
+ },
+ post: function($scope, $element) {
+ log('post(' + $element.text() + ')');
+ }
+ }
+ };
});
- }
- }));
- });
- inject(function($compile) {
- element = $compile('
{{$id}}
')($rootScope);
- $rootScope.$apply();
- expect(element.text()).toBe('' + $rootScope.$id);
- });
+ });
+ inject(function(log, $rootScope, $compile) {
+ element = $compile('
unicorn!
')($rootScope);
+ $rootScope.$apply();
+ expect(log).toEqual('pre(); post(unicorn!)');
+ });
+ });
- });
- it('should expose the directive controller to transcluded children', function() {
- var capturedChildCtrl;
- module(function() {
- directive('transclude', valueFn({
- transclude: 'content',
- controller: function() {
- },
- link: function(scope, element, attr, ctrl, $transclude) {
- $transclude(function(clone) {
- element.append(clone);
+ it('should make the result of a transclusion available to the parent directive in post-linking phase' +
+ '(templateUrl)', function() {
+ // when compiling an async directive the transclusion is always processed before the directive
+ // this is different compared to sync directive. delaying the transclusion makes little sense.
+
+ module(function() {
+ directive('trans', function(log) {
+ return {
+ transclude: true,
+ templateUrl: 'trans.html',
+ link: {
+ pre: function($scope, $element) {
+ log('pre(' + $element.text() + ')');
+ },
+ post: function($scope, $element) {
+ log('post(' + $element.text() + ')');
+ }
+ }
+ };
});
- }
- }));
- directive('child', valueFn({
- require: '^transclude',
- link: function(scope, element, attr, ctrl) {
- capturedChildCtrl = ctrl;
- }
- }));
- });
- inject(function($compile) {
- element = $compile('
')($rootScope);
- expect(capturedChildCtrl).toBeTruthy();
- });
- });
+ });
+ inject(function(log, $rootScope, $compile, $templateCache) {
+ $templateCache.put('trans.html', '
');
+ element = $compile('
unicorn!
')($rootScope);
+ $rootScope.$apply();
+ expect(log).toEqual('pre(); post(unicorn!)');
+ });
+ });
- // See issue https://github.com/angular/angular.js/issues/14924
- it('should not process top-level transcluded text nodes merged into their sibling',
- function() {
- module(function() {
- directive('transclude', valueFn({
- template: '
',
- transclude: true,
- scope: {}
- }));
+
+ it('should make the result of a transclusion available to the parent *replace* directive in post-linking phase' +
+ '(template)', function() {
+ module(function() {
+ directive('replacedTrans', function(log) {
+ return {
+ transclude: true,
+ replace: true,
+ template: '
',
+ link: {
+ pre: function($scope, $element) {
+ log('pre(' + $element.text() + ')');
+ },
+ post: function($scope, $element) {
+ log('post(' + $element.text() + ')');
+ }
+ }
+ };
+ });
+ });
+ inject(function(log, $rootScope, $compile) {
+ element = $compile('
unicorn!
')($rootScope);
+ $rootScope.$apply();
+ expect(log).toEqual('pre(); post(unicorn!)');
+ });
});
- inject(function($compile) {
- element = jqLite('
');
- element[0].appendChild(document.createTextNode('1{{ value }}'));
- element[0].appendChild(document.createTextNode('2{{ value }}'));
- element[0].appendChild(document.createTextNode('3{{ value }}'));
- var initialWatcherCount = $rootScope.$countWatchers();
- $compile(element)($rootScope);
- $rootScope.$apply('value = 0');
- var newWatcherCount = $rootScope.$countWatchers() - initialWatcherCount;
+ it('should make the result of a transclusion available to the parent *replace* directive in post-linking phase' +
+ ' (templateUrl)', function() {
+ module(function() {
+ directive('replacedTrans', function(log) {
+ return {
+ transclude: true,
+ replace: true,
+ templateUrl: 'trans.html',
+ link: {
+ pre: function($scope, $element) {
+ log('pre(' + $element.text() + ')');
+ },
+ post: function($scope, $element) {
+ log('post(' + $element.text() + ')');
+ }
+ }
+ };
+ });
+ });
+ inject(function(log, $rootScope, $compile, $templateCache) {
+ $templateCache.put('trans.html', '
');
- expect(element.text()).toBe('102030');
- expect(newWatcherCount).toBe(3);
+ element = $compile('
unicorn!
')($rootScope);
+ $rootScope.$apply();
+ expect(log).toEqual('pre(); post(unicorn!)');
+ });
});
- }
- );
+ it('should copy the directive controller to all clones', function() {
+ var transcludeCtrl, cloneCount = 2;
+ module(function() {
+ directive('transclude', valueFn({
+ transclude: 'content',
+ controller: function($transclude) {
+ transcludeCtrl = this;
+ },
+ link: function(scope, el, attr, ctrl, $transclude) {
+ var i;
+ for (i = 0; i < cloneCount; i++) {
+ $transclude(cloneAttach);
+ }
- // see issue https://github.com/angular/angular.js/issues/9413
- describe('passing a parent bound transclude function to the link ' +
- 'function returned from `$compile`', function() {
+ function cloneAttach(clone) {
+ el.append(clone);
+ }
+ }
+ }));
+ });
+ inject(function($compile) {
+ element = $compile('
')($rootScope);
+ var children = element.children(), i;
+ expect(transcludeCtrl).toBeDefined();
- beforeEach(module(function() {
- directive('lazyCompile', function($compile) {
- return {
- compile: function(tElement, tAttrs) {
- var content = tElement.contents();
- tElement.empty();
- return function(scope, element, attrs, ctrls, transcludeFn) {
- element.append(content);
- $compile(content)(scope, undefined, {
- parentBoundTranscludeFn: transcludeFn
- });
- };
+ expect(element.data('$transcludeController')).toBe(transcludeCtrl);
+ for (i = 0; i < cloneCount; i++) {
+ expect(children.eq(i).data('$transcludeController')).toBeUndefined();
}
- };
+ });
});
- directive('toggle', valueFn({
- scope: {t: '=toggle'},
- transclude: true,
- template: '
'
- }));
- }));
- it('should preserve the bound scope', function() {
+ it('should provide the $transclude controller local as 5th argument to the pre and post-link function', function() {
+ var ctrlTransclude, preLinkTransclude, postLinkTransclude;
+ module(function() {
+ directive('transclude', valueFn({
+ transclude: 'content',
+ controller: function($transclude) {
+ ctrlTransclude = $transclude;
+ },
+ compile: function() {
+ return {
+ pre: function(scope, el, attr, ctrl, $transclude) {
+ preLinkTransclude = $transclude;
+ },
+ post: function(scope, el, attr, ctrl, $transclude) {
+ postLinkTransclude = $transclude;
+ }
+ };
+ }
+ }));
+ });
+ inject(function($compile) {
+ element = $compile('
')($rootScope);
+ expect(ctrlTransclude).toBeDefined();
+ expect(ctrlTransclude).toBe(preLinkTransclude);
+ expect(ctrlTransclude).toBe(postLinkTransclude);
+ });
+ });
- inject(function($compile, $rootScope) {
- element = $compile(
- '
' +
- '
' +
- '
' +
- 'SuccessError' +
- '
' +
- '
')($rootScope);
+ it('should allow an optional scope argument in $transclude', function() {
+ var capturedChildCtrl;
+ module(function() {
+ directive('transclude', valueFn({
+ transclude: 'content',
+ link: function(scope, element, attr, ctrl, $transclude) {
+ $transclude(scope, function(clone) {
+ element.append(clone);
+ });
+ }
+ }));
+ });
+ inject(function($compile) {
+ element = $compile('
{{$id}}
')($rootScope);
+ $rootScope.$apply();
+ expect(element.text()).toBe('' + $rootScope.$id);
+ });
- $rootScope.$apply('t = false');
- expect($rootScope.$countChildScopes()).toBe(1);
- expect(element.text()).toBe('');
+ });
- $rootScope.$apply('t = true');
- expect($rootScope.$countChildScopes()).toBe(4);
- expect(element.text()).toBe('Success');
+ it('should expose the directive controller to transcluded children', function() {
+ var capturedChildCtrl;
+ module(function() {
+ directive('transclude', valueFn({
+ transclude: 'content',
+ controller: function() {
+ },
+ link: function(scope, element, attr, ctrl, $transclude) {
+ $transclude(function(clone) {
+ element.append(clone);
+ });
+ }
+ }));
+ directive('child', valueFn({
+ require: '^transclude',
+ link: function(scope, element, attr, ctrl) {
+ capturedChildCtrl = ctrl;
+ }
+ }));
+ });
+ inject(function($compile) {
+ element = $compile('
')($rootScope);
+ expect(capturedChildCtrl).toBeTruthy();
+ });
+ });
- $rootScope.$apply('t = false');
- expect($rootScope.$countChildScopes()).toBe(1);
- expect(element.text()).toBe('');
- $rootScope.$apply('t = true');
- expect($rootScope.$countChildScopes()).toBe(4);
- expect(element.text()).toBe('Success');
- });
- });
+ // See issue https://github.com/angular/angular.js/issues/14924
+ it('should not process top-level transcluded text nodes merged into their sibling',
+ function() {
+ module(function() {
+ directive('transclude', valueFn({
+ template: '
',
+ transclude: true,
+ scope: {}
+ }));
+ });
+ inject(function($compile) {
+ element = jqLite('
');
+ element[0].appendChild(document.createTextNode('1{{ value }}'));
+ element[0].appendChild(document.createTextNode('2{{ value }}'));
+ element[0].appendChild(document.createTextNode('3{{ value }}'));
- it('should preserve the bound scope when using recursive transclusion', function() {
+ var initialWatcherCount = $rootScope.$countWatchers();
+ $compile(element)($rootScope);
+ $rootScope.$apply('value = 0');
+ var newWatcherCount = $rootScope.$countWatchers() - initialWatcherCount;
- directive('recursiveTransclude', valueFn({
- transclude: true,
- template: '
'
- }));
+ expect(element.text()).toBe('102030');
+ expect(newWatcherCount).toBe(3);
+ });
+ }
+ );
- inject(function($compile, $rootScope) {
- element = $compile(
- '
' +
- '
' +
- '
' +
- '
' +
- 'SuccessError' +
- '
' +
- '
' +
- '
')($rootScope);
- $rootScope.$apply('t = false');
- expect($rootScope.$countChildScopes()).toBe(1);
- expect(element.text()).toBe('');
+ // see issue https://github.com/angular/angular.js/issues/9413
+ describe('passing a parent bound transclude function to the link ' +
+ 'function returned from `$compile`', function() {
- $rootScope.$apply('t = true');
- expect($rootScope.$countChildScopes()).toBe(4);
- expect(element.text()).toBe('Success');
+ beforeEach(module(function() {
+ directive('lazyCompile', function($compile) {
+ return {
+ compile: function(tElement, tAttrs) {
+ var content = tElement.contents();
+ tElement.empty();
+ return function(scope, element, attrs, ctrls, transcludeFn) {
+ element.append(content);
+ $compile(content)(scope, undefined, {
+ parentBoundTranscludeFn: transcludeFn
+ });
+ };
+ }
+ };
+ });
+ directive('toggle', valueFn({
+ scope: {t: '=toggle'},
+ transclude: true,
+ template: '
'
+ }));
+ }));
- $rootScope.$apply('t = false');
- expect($rootScope.$countChildScopes()).toBe(1);
- expect(element.text()).toBe('');
+ it('should preserve the bound scope', function() {
- $rootScope.$apply('t = true');
- expect($rootScope.$countChildScopes()).toBe(4);
- expect(element.text()).toBe('Success');
- });
- });
- });
+ inject(function($compile, $rootScope) {
+ element = $compile(
+ '
' +
+ '
' +
+ '
' +
+ 'SuccessError' +
+ '
' +
+ '
')($rootScope);
+
+ $rootScope.$apply('t = false');
+ expect($rootScope.$countChildScopes()).toBe(1);
+ expect(element.text()).toBe('');
+
+ $rootScope.$apply('t = true');
+ expect($rootScope.$countChildScopes()).toBe(4);
+ expect(element.text()).toBe('Success');
+
+ $rootScope.$apply('t = false');
+ expect($rootScope.$countChildScopes()).toBe(1);
+ expect(element.text()).toBe('');
+
+ $rootScope.$apply('t = true');
+ expect($rootScope.$countChildScopes()).toBe(4);
+ expect(element.text()).toBe('Success');
+ });
+ });
- // see issue https://github.com/angular/angular.js/issues/9095
- describe('removing a transcluded element', function() {
+ it('should preserve the bound scope when using recursive transclusion', function() {
- beforeEach(module(function() {
- directive('toggle', function() {
- return {
- transclude: true,
- template: '
'
- };
+ directive('recursiveTransclude', valueFn({
+ transclude: true,
+ template: '
'
+ }));
+
+ inject(function($compile, $rootScope) {
+ element = $compile(
+ '
' +
+ '
' +
+ '
' +
+ '
' +
+ 'SuccessError' +
+ '
' +
+ '
' +
+ '
')($rootScope);
+
+ $rootScope.$apply('t = false');
+ expect($rootScope.$countChildScopes()).toBe(1);
+ expect(element.text()).toBe('');
+
+ $rootScope.$apply('t = true');
+ expect($rootScope.$countChildScopes()).toBe(4);
+ expect(element.text()).toBe('Success');
+
+ $rootScope.$apply('t = false');
+ expect($rootScope.$countChildScopes()).toBe(1);
+ expect(element.text()).toBe('');
+
+ $rootScope.$apply('t = true');
+ expect($rootScope.$countChildScopes()).toBe(4);
+ expect(element.text()).toBe('Success');
+ });
+ });
});
- }));
- it('should not leak the transclude scope when the transcluded content is an element transclusion directive',
- inject(function($compile, $rootScope) {
+ // see issue https://github.com/angular/angular.js/issues/9095
+ describe('removing a transcluded element', function() {
- element = $compile(
- '
'
- )($rootScope);
-
- $rootScope.$apply('t = true');
- expect(element.text()).toContain('msg-1');
- // Expected scopes: $rootScope, ngIf, transclusion, ngRepeat
- expect($rootScope.$countChildScopes()).toBe(3);
-
- $rootScope.$apply('t = false');
- expect(element.text()).not.toContain('msg-1');
- // Expected scopes: $rootScope
- expect($rootScope.$countChildScopes()).toBe(0);
-
- $rootScope.$apply('t = true');
- expect(element.text()).toContain('msg-1');
- // Expected scopes: $rootScope, ngIf, transclusion, ngRepeat
- expect($rootScope.$countChildScopes()).toBe(3);
-
- $rootScope.$apply('t = false');
- expect(element.text()).not.toContain('msg-1');
- // Expected scopes: $rootScope
- expect($rootScope.$countChildScopes()).toBe(0);
- }));
+ beforeEach(module(function() {
+ directive('toggle', function() {
+ return {
+ transclude: true,
+ template: '
'
+ };
+ });
+ }));
- it('should not leak the transclude scope when the transcluded content is an multi-element transclusion directive',
- inject(function($compile, $rootScope) {
+ it('should not leak the transclude scope when the transcluded content is an element transclusion directive',
+ inject(function($compile, $rootScope) {
- element = $compile(
- '
' +
- '
{{ msg }}
' +
- '
{{ msg }}
' +
- '
'
- )($rootScope);
-
- $rootScope.$apply('t = true');
- expect(element.text()).toContain('msg-1msg-1');
- // Expected scopes: $rootScope, ngIf, transclusion, ngRepeat
- expect($rootScope.$countChildScopes()).toBe(3);
-
- $rootScope.$apply('t = false');
- expect(element.text()).not.toContain('msg-1msg-1');
- // Expected scopes: $rootScope
- expect($rootScope.$countChildScopes()).toBe(0);
-
- $rootScope.$apply('t = true');
- expect(element.text()).toContain('msg-1msg-1');
- // Expected scopes: $rootScope, ngIf, transclusion, ngRepeat
- expect($rootScope.$countChildScopes()).toBe(3);
-
- $rootScope.$apply('t = false');
- expect(element.text()).not.toContain('msg-1msg-1');
- // Expected scopes: $rootScope
- expect($rootScope.$countChildScopes()).toBe(0);
- }));
+ element = $compile(
+ '
'
+ )($rootScope);
+ $rootScope.$apply('t = true');
+ expect(element.text()).toContain('msg-1');
+ // Expected scopes: $rootScope, ngIf, transclusion, ngRepeat
+ expect($rootScope.$countChildScopes()).toBe(3);
+
+ $rootScope.$apply('t = false');
+ expect(element.text()).not.toContain('msg-1');
+ // Expected scopes: $rootScope
+ expect($rootScope.$countChildScopes()).toBe(0);
+
+ $rootScope.$apply('t = true');
+ expect(element.text()).toContain('msg-1');
+ // Expected scopes: $rootScope, ngIf, transclusion, ngRepeat
+ expect($rootScope.$countChildScopes()).toBe(3);
+
+ $rootScope.$apply('t = false');
+ expect(element.text()).not.toContain('msg-1');
+ // Expected scopes: $rootScope
+ expect($rootScope.$countChildScopes()).toBe(0);
+ }));
- it('should not leak the transclude scope if the transcluded contains only comments',
- inject(function($compile, $rootScope) {
- element = $compile(
- '
' +
- '' +
- '
'
- )($rootScope);
-
- $rootScope.$apply('t = true');
- expect(element.html()).toContain('some comment');
- // Expected scopes: $rootScope, ngIf, transclusion
- expect($rootScope.$countChildScopes()).toBe(2);
-
- $rootScope.$apply('t = false');
- expect(element.html()).not.toContain('some comment');
- // Expected scopes: $rootScope
- expect($rootScope.$countChildScopes()).toBe(0);
-
- $rootScope.$apply('t = true');
- expect(element.html()).toContain('some comment');
- // Expected scopes: $rootScope, ngIf, transclusion
- expect($rootScope.$countChildScopes()).toBe(2);
-
- $rootScope.$apply('t = false');
- expect(element.html()).not.toContain('some comment');
- // Expected scopes: $rootScope
- expect($rootScope.$countChildScopes()).toBe(0);
- }));
+ it('should not leak the transclude scope when the transcluded content is an multi-element transclusion directive',
+ inject(function($compile, $rootScope) {
- it('should not leak the transclude scope if the transcluded contains only text nodes',
- inject(function($compile, $rootScope) {
+ element = $compile(
+ '
' +
+ '
{{ msg }}
' +
+ '
{{ msg }}
' +
+ '
'
+ )($rootScope);
- element = $compile(
- '
' +
- 'some text' +
- '
'
- )($rootScope);
-
- $rootScope.$apply('t = true');
- expect(element.html()).toContain('some text');
- // Expected scopes: $rootScope, ngIf, transclusion
- expect($rootScope.$countChildScopes()).toBe(2);
-
- $rootScope.$apply('t = false');
- expect(element.html()).not.toContain('some text');
- // Expected scopes: $rootScope
- expect($rootScope.$countChildScopes()).toBe(0);
-
- $rootScope.$apply('t = true');
- expect(element.html()).toContain('some text');
- // Expected scopes: $rootScope, ngIf, transclusion
- expect($rootScope.$countChildScopes()).toBe(2);
-
- $rootScope.$apply('t = false');
- expect(element.html()).not.toContain('some text');
- // Expected scopes: $rootScope
- expect($rootScope.$countChildScopes()).toBe(0);
- }));
+ $rootScope.$apply('t = true');
+ expect(element.text()).toContain('msg-1msg-1');
+ // Expected scopes: $rootScope, ngIf, transclusion, ngRepeat
+ expect($rootScope.$countChildScopes()).toBe(3);
+
+ $rootScope.$apply('t = false');
+ expect(element.text()).not.toContain('msg-1msg-1');
+ // Expected scopes: $rootScope
+ expect($rootScope.$countChildScopes()).toBe(0);
+
+ $rootScope.$apply('t = true');
+ expect(element.text()).toContain('msg-1msg-1');
+ // Expected scopes: $rootScope, ngIf, transclusion, ngRepeat
+ expect($rootScope.$countChildScopes()).toBe(3);
+
+ $rootScope.$apply('t = false');
+ expect(element.text()).not.toContain('msg-1msg-1');
+ // Expected scopes: $rootScope
+ expect($rootScope.$countChildScopes()).toBe(0);
+ }));
- it('should mark as destroyed all sub scopes of the scope being destroyed',
- inject(function($compile, $rootScope) {
- element = $compile(
- '
'
- )($rootScope);
+ it('should not leak the transclude scope if the transcluded contains only comments',
+ inject(function($compile, $rootScope) {
- $rootScope.$apply('t = true');
- var childScopes = getChildScopes($rootScope);
+ element = $compile(
+ '
' +
+ '' +
+ '
'
+ )($rootScope);
- $rootScope.$apply('t = false');
- for (var i = 0; i < childScopes.length; ++i) {
- expect(childScopes[i].$$destroyed).toBe(true);
- }
- }));
- });
+ $rootScope.$apply('t = true');
+ expect(element.html()).toContain('some comment');
+ // Expected scopes: $rootScope, ngIf, transclusion
+ expect($rootScope.$countChildScopes()).toBe(2);
+
+ $rootScope.$apply('t = false');
+ expect(element.html()).not.toContain('some comment');
+ // Expected scopes: $rootScope
+ expect($rootScope.$countChildScopes()).toBe(0);
+
+ $rootScope.$apply('t = true');
+ expect(element.html()).toContain('some comment');
+ // Expected scopes: $rootScope, ngIf, transclusion
+ expect($rootScope.$countChildScopes()).toBe(2);
+
+ $rootScope.$apply('t = false');
+ expect(element.html()).not.toContain('some comment');
+ // Expected scopes: $rootScope
+ expect($rootScope.$countChildScopes()).toBe(0);
+ }));
+ it('should not leak the transclude scope if the transcluded contains only text nodes',
+ inject(function($compile, $rootScope) {
- describe('nested transcludes', function() {
+ element = $compile(
+ '
' +
+ 'some text' +
+ '
'
+ )($rootScope);
- beforeEach(module(function($compileProvider) {
+ $rootScope.$apply('t = true');
+ expect(element.html()).toContain('some text');
+ // Expected scopes: $rootScope, ngIf, transclusion
+ expect($rootScope.$countChildScopes()).toBe(2);
+
+ $rootScope.$apply('t = false');
+ expect(element.html()).not.toContain('some text');
+ // Expected scopes: $rootScope
+ expect($rootScope.$countChildScopes()).toBe(0);
+
+ $rootScope.$apply('t = true');
+ expect(element.html()).toContain('some text');
+ // Expected scopes: $rootScope, ngIf, transclusion
+ expect($rootScope.$countChildScopes()).toBe(2);
+
+ $rootScope.$apply('t = false');
+ expect(element.html()).not.toContain('some text');
+ // Expected scopes: $rootScope
+ expect($rootScope.$countChildScopes()).toBe(0);
+ }));
- $compileProvider.directive('noop', valueFn({}));
+ it('should mark as destroyed all sub scopes of the scope being destroyed',
+ inject(function($compile, $rootScope) {
- $compileProvider.directive('sync', valueFn({
- template: '
',
- transclude: true
- }));
+ element = $compile(
+ '
'
+ )($rootScope);
- $compileProvider.directive('async', valueFn({
- templateUrl: 'async',
- transclude: true
- }));
+ $rootScope.$apply('t = true');
+ var childScopes = getChildScopes($rootScope);
- $compileProvider.directive('syncSync', valueFn({
- template: '
',
- transclude: true
- }));
+ $rootScope.$apply('t = false');
+ for (var i = 0; i < childScopes.length; ++i) {
+ expect(childScopes[i].$$destroyed).toBe(true);
+ }
+ }));
+ });
- $compileProvider.directive('syncAsync', valueFn({
- template: '
',
- transclude: true
- }));
- $compileProvider.directive('asyncSync', valueFn({
- templateUrl: 'asyncSync',
- transclude: true
- }));
+ describe('nested transcludes', function() {
- $compileProvider.directive('asyncAsync', valueFn({
- templateUrl: 'asyncAsync',
- transclude: true
- }));
+ beforeEach(module(function($compileProvider) {
- }));
+ $compileProvider.directive('noop', valueFn({}));
- beforeEach(inject(function($templateCache) {
- $templateCache.put('async', '
');
- $templateCache.put('asyncSync', '
');
- $templateCache.put('asyncAsync', '
');
- }));
+ $compileProvider.directive('sync', valueFn({
+ template: '
',
+ transclude: true
+ }));
+ $compileProvider.directive('async', valueFn({
+ templateUrl: 'async',
+ transclude: true
+ }));
- it('should allow nested transclude directives with sync template containing sync template', inject(function($compile, $rootScope) {
- element = $compile('
transcluded content
')($rootScope);
- $rootScope.$digest();
- expect(element.text()).toEqual('transcluded content');
- }));
+ $compileProvider.directive('syncSync', valueFn({
+ template: '
',
+ transclude: true
+ }));
- it('should allow nested transclude directives with sync template containing async template', inject(function($compile, $rootScope) {
- element = $compile('
transcluded content
')($rootScope);
- $rootScope.$digest();
- expect(element.text()).toEqual('transcluded content');
- }));
+ $compileProvider.directive('syncAsync', valueFn({
+ template: '
',
+ transclude: true
+ }));
- it('should allow nested transclude directives with async template containing sync template', inject(function($compile, $rootScope) {
- element = $compile('
transcluded content
')($rootScope);
- $rootScope.$digest();
- expect(element.text()).toEqual('transcluded content');
- }));
+ $compileProvider.directive('asyncSync', valueFn({
+ templateUrl: 'asyncSync',
+ transclude: true
+ }));
- it('should allow nested transclude directives with async template containing asynch template', inject(function($compile, $rootScope) {
- element = $compile('
transcluded content
')($rootScope);
- $rootScope.$digest();
- expect(element.text()).toEqual('transcluded content');
- }));
+ $compileProvider.directive('asyncAsync', valueFn({
+ templateUrl: 'asyncAsync',
+ transclude: true
+ }));
+ }));
- it('should not leak memory with nested transclusion', function() {
- inject(function($compile, $rootScope) {
- var size, initialSize = jqLiteCacheSize();
+ beforeEach(inject(function($templateCache) {
+ $templateCache.put('async', '
');
+ $templateCache.put('asyncSync', '
');
+ $templateCache.put('asyncAsync', '
');
+ }));
- element = jqLite('
');
- $compile(element)($rootScope.$new());
- $rootScope.nums = [0,1,2];
- $rootScope.$apply();
- size = jqLiteCacheSize();
+ it('should allow nested transclude directives with sync template containing sync template', inject(function($compile, $rootScope) {
+ element = $compile('
transcluded content
')($rootScope);
+ $rootScope.$digest();
+ expect(element.text()).toEqual('transcluded content');
+ }));
- $rootScope.nums = [3,4,5];
- $rootScope.$apply();
- expect(jqLiteCacheSize()).toEqual(size);
+ it('should allow nested transclude directives with sync template containing async template', inject(function($compile, $rootScope) {
+ element = $compile('
transcluded content
')($rootScope);
+ $rootScope.$digest();
+ expect(element.text()).toEqual('transcluded content');
+ }));
- element.remove();
- expect(jqLiteCacheSize()).toEqual(initialSize);
- });
- });
- });
+ it('should allow nested transclude directives with async template containing sync template', inject(function($compile, $rootScope) {
+ element = $compile('
transcluded content
')($rootScope);
+ $rootScope.$digest();
+ expect(element.text()).toEqual('transcluded content');
+ }));
+ it('should allow nested transclude directives with async template containing asynch template', inject(function($compile, $rootScope) {
+ element = $compile('
transcluded content
')($rootScope);
+ $rootScope.$digest();
+ expect(element.text()).toEqual('transcluded content');
+ }));
- describe('nested isolated scope transcludes', function() {
- beforeEach(module(function($compileProvider) {
- $compileProvider.directive('trans', valueFn({
- restrict: 'E',
- template: '
',
- transclude: true
- }));
+ it('should not leak memory with nested transclusion', function() {
+ inject(function($compile, $rootScope) {
+ var size, initialSize = jqLiteCacheSize();
- $compileProvider.directive('transAsync', valueFn({
- restrict: 'E',
- templateUrl: 'transAsync',
- transclude: true
- }));
+ element = jqLite('
');
+ $compile(element)($rootScope.$new());
- $compileProvider.directive('iso', valueFn({
- restrict: 'E',
- transclude: true,
- template: '
',
- scope: {}
- }));
- $compileProvider.directive('isoAsync1', valueFn({
- restrict: 'E',
- transclude: true,
- template: '
',
- scope: {}
- }));
- $compileProvider.directive('isoAsync2', valueFn({
- restrict: 'E',
- transclude: true,
- templateUrl: 'isoAsync',
- scope: {}
- }));
- }));
+ $rootScope.nums = [0,1,2];
+ $rootScope.$apply();
+ size = jqLiteCacheSize();
- beforeEach(inject(function($templateCache) {
- $templateCache.put('transAsync', '
');
- $templateCache.put('isoAsync', '
');
- }));
+ $rootScope.nums = [3,4,5];
+ $rootScope.$apply();
+ expect(jqLiteCacheSize()).toEqual(size);
+
+ element.remove();
+ expect(jqLiteCacheSize()).toEqual(initialSize);
+ });
+ });
+ });
- it('should pass the outer scope to the transclude on the isolated template sync-sync', inject(function($compile, $rootScope) {
+ describe('nested isolated scope transcludes', function() {
+ beforeEach(module(function($compileProvider) {
- $rootScope.val = 'transcluded content';
- element = $compile('
')($rootScope);
- $rootScope.$digest();
- expect(element.text()).toEqual('transcluded content');
- }));
+ $compileProvider.directive('trans', valueFn({
+ restrict: 'E',
+ template: '
',
+ transclude: true
+ }));
- it('should pass the outer scope to the transclude on the isolated template async-sync', inject(function($compile, $rootScope) {
+ $compileProvider.directive('transAsync', valueFn({
+ restrict: 'E',
+ templateUrl: 'transAsync',
+ transclude: true
+ }));
- $rootScope.val = 'transcluded content';
- element = $compile('
')($rootScope);
- $rootScope.$digest();
- expect(element.text()).toEqual('transcluded content');
- }));
+ $compileProvider.directive('iso', valueFn({
+ restrict: 'E',
+ transclude: true,
+ template: '
',
+ scope: {}
+ }));
+ $compileProvider.directive('isoAsync1', valueFn({
+ restrict: 'E',
+ transclude: true,
+ template: '
',
+ scope: {}
+ }));
+ $compileProvider.directive('isoAsync2', valueFn({
+ restrict: 'E',
+ transclude: true,
+ templateUrl: 'isoAsync',
+ scope: {}
+ }));
+ }));
- it('should pass the outer scope to the transclude on the isolated template async-async', inject(function($compile, $rootScope) {
+ beforeEach(inject(function($templateCache) {
+ $templateCache.put('transAsync', '
');
+ $templateCache.put('isoAsync', '
');
+ }));
- $rootScope.val = 'transcluded content';
- element = $compile('
')($rootScope);
- $rootScope.$digest();
- expect(element.text()).toEqual('transcluded content');
- }));
- });
+ it('should pass the outer scope to the transclude on the isolated template sync-sync', inject(function($compile, $rootScope) {
- describe('multiple siblings receiving transclusion', function() {
+ $rootScope.val = 'transcluded content';
+ element = $compile('
')($rootScope);
+ $rootScope.$digest();
+ expect(element.text()).toEqual('transcluded content');
+ }));
- it('should only receive transclude from parent', function() {
+ it('should pass the outer scope to the transclude on the isolated template async-sync', inject(function($compile, $rootScope) {
- module(function($compileProvider) {
+ $rootScope.val = 'transcluded content';
+ element = $compile('
')($rootScope);
+ $rootScope.$digest();
+ expect(element.text()).toEqual('transcluded content');
+ }));
- $compileProvider.directive('myExample', valueFn({
- scope: {},
- link: function link(scope, element, attrs) {
- var foo = element[0].querySelector('.foo');
- scope.children = angular.element(foo).children().length;
- },
- template: '
' +
- '
myExample {{children}}!
' +
- '
has children
' +
- '
' +
- '
',
- transclude: true
+ it('should pass the outer scope to the transclude on the isolated template async-async', inject(function($compile, $rootScope) {
+ $rootScope.val = 'transcluded content';
+ element = $compile('
')($rootScope);
+ $rootScope.$digest();
+ expect(element.text()).toEqual('transcluded content');
}));
});
- inject(function($compile, $rootScope) {
- var element = $compile('
')($rootScope);
- $rootScope.$digest();
- expect(element.text()).toEqual('myExample 0!');
- dealoc(element);
+ describe('multiple siblings receiving transclusion', function() {
- element = $compile('
')($rootScope);
- $rootScope.$digest();
- expect(element.text()).toEqual('myExample 1!has children');
- dealoc(element);
+ it('should only receive transclude from parent', function() {
+
+ module(function($compileProvider) {
+
+ $compileProvider.directive('myExample', valueFn({
+ scope: {},
+ link: function link(scope, element, attrs) {
+ var foo = element[0].querySelector('.foo');
+ scope.children = angular.element(foo).children().length;
+ },
+ template: '
' +
+ '
myExample {{children}}!
' +
+ '
has children
' +
+ '
' +
+ '
',
+ transclude: true
+
+ }));
+
+ });
+
+ inject(function($compile, $rootScope) {
+ var element = $compile('
')($rootScope);
+ $rootScope.$digest();
+ expect(element.text()).toEqual('myExample 0!');
+ dealoc(element);
+
+ element = $compile('
')($rootScope);
+ $rootScope.$digest();
+ expect(element.text()).toEqual('myExample 1!has children');
+ dealoc(element);
+ });
+ });
});
});
- });
- });
- describe('element transclusion', function() {
+ describe('element transclusion', function() {
- it('should support basic element transclusion', function() {
- module(function() {
- directive('trans', function(log) {
- return {
- transclude: 'element',
- priority: 2,
- controller: function($transclude) { this.$transclude = $transclude; },
- compile: function(element, attrs, template) {
- log('compile: ' + angular.mock.dump(element));
- return function(scope, element, attrs, ctrl) {
- log('link');
- var cursor = element;
- template(scope.$new(), function(clone) {cursor.after(cursor = clone);});
- ctrl.$transclude(function(clone) {cursor.after(clone);});
+ it('should support basic element transclusion', function() {
+ module(function() {
+ directive('trans', function(log) {
+ return {
+ transclude: 'element',
+ priority: 2,
+ controller: function($transclude) { this.$transclude = $transclude; },
+ compile: function(element, attrs, template) {
+ log('compile: ' + angular.mock.dump(element));
+ return function(scope, element, attrs, ctrl) {
+ log('link');
+ var cursor = element;
+ template(scope.$new(), function(clone) {cursor.after(cursor = clone);});
+ ctrl.$transclude(function(clone) {cursor.after(clone);});
+ };
+ }
};
- }
- };
+ });
+ });
+ inject(function(log, $rootScope, $compile) {
+ element = $compile('
')($rootScope);
+ $rootScope.$apply();
+ expect(log).toEqual('compile: ; link; LOG; LOG; HIGH');
+ expect(element.text()).toEqual('1-2;1-3;');
+ });
});
- });
- inject(function(log, $rootScope, $compile) {
- element = $compile('
')($rootScope);
- $rootScope.$apply();
- expect(log).toEqual('compile: ; link; LOG; LOG; HIGH');
- expect(element.text()).toEqual('1-2;1-3;');
- });
- });
- it('should only allow one element transclusion per element', function() {
- module(function() {
- directive('first', valueFn({
- transclude: 'element'
- }));
- directive('second', valueFn({
- transclude: 'element'
- }));
- });
- inject(function($compile) {
- expect(function() {
- $compile('
');
- }).toThrowMinErr('$compile', 'multidir', 'Multiple directives [first, second] asking for transclusion on: ' +
- '');
- });
- });
+ it('should only allow one element transclusion per element', function() {
+ module(function() {
+ directive('first', valueFn({
+ transclude: 'element'
+ }));
+ directive('second', valueFn({
+ transclude: 'element'
+ }));
+ });
+ inject(function($compile) {
+ expect(function() {
+ $compile('
');
+ }).toThrowMinErr('$compile', 'multidir', 'Multiple directives [first, second] asking for transclusion on: ' +
+ '');
+ });
+ });
- it('should only allow one element transclusion per element when directives have different priorities', function() {
- // we restart compilation in this case and we need to remember the duplicates during the second compile
- // regression #3893
- module(function() {
- directive('first', valueFn({
- transclude: 'element',
- priority: 100
- }));
- directive('second', valueFn({
- transclude: 'element'
- }));
- });
- inject(function($compile) {
- expect(function() {
- $compile('
');
- }).toThrowMinErr('$compile', 'multidir', /Multiple directives \[first, second\] asking for transclusion on:
');
+ }).toThrowMinErr('$compile', 'multidir', /Multiple directives \[first, second\] asking for transclusion on:
template.html');
- $compile('
');
- expect(function() {
- $httpBackend.flush();
- }).toThrowMinErr('$compile', 'multidir', /Multiple directives \[first, second\] asking for transclusion on:
template.html
');
+ $compile('
');
+ expect(function() {
+ $httpBackend.flush();
+ }).toThrowMinErr('$compile', 'multidir', /Multiple directives \[first, second\] asking for transclusion on:
',
- replace: true
- }));
- directive('first', valueFn({
- transclude: 'element',
- priority: 100
- }));
- directive('second', valueFn({
- transclude: 'element'
- }));
- });
- inject(function($compile) {
- expect(function() {
- $compile('
');
- }).toThrowMinErr('$compile', 'multidir', /Multiple directives \[first, second\] asking for transclusion on:
',
+ replace: true
+ }));
+ directive('first', valueFn({
+ transclude: 'element',
+ priority: 100
+ }));
+ directive('second', valueFn({
+ transclude: 'element'
+ }));
+ });
+ inject(function($compile) {
+ expect(function() {
+ $compile('
');
+ }).toThrowMinErr('$compile', 'multidir', /Multiple directives \[first, second\] asking for transclusion on:
before
after
').contents();
- expect(element.length).toEqual(3);
- expect(nodeName_(element[1])).toBe('div');
- $compile(element)($rootScope);
- expect(nodeName_(element[1])).toBe('#comment');
- expect(nodeName_(comment)).toBe('#comment');
- });
- });
+ it('should support transcluded element on root content', function() {
+ var comment;
+ module(function() {
+ directive('transclude', valueFn({
+ transclude: 'element',
+ compile: function(element, attr, linker) {
+ return function(scope, element, attr) {
+ comment = element;
+ };
+ }
+ }));
+ });
+ inject(function($compile, $rootScope) {
+ var element = jqLite('
').contents();
+ expect(element.length).toEqual(3);
+ expect(nodeName_(element[1])).toBe('div');
+ $compile(element)($rootScope);
+ expect(nodeName_(element[1])).toBe('#comment');
+ expect(nodeName_(comment)).toBe('#comment');
+ });
+ });
- it('should terminate compilation only for element trasclusion', function() {
- module(function() {
- directive('elementTrans', function(log) {
- return {
- transclude: 'element',
- priority: 50,
- compile: log.fn('compile:elementTrans')
- };
- });
- directive('regularTrans', function(log) {
- return {
- transclude: true,
- priority: 50,
- compile: log.fn('compile:regularTrans')
- };
+ it('should terminate compilation only for element trasclusion', function() {
+ module(function() {
+ directive('elementTrans', function(log) {
+ return {
+ transclude: 'element',
+ priority: 50,
+ compile: log.fn('compile:elementTrans')
+ };
+ });
+ directive('regularTrans', function(log) {
+ return {
+ transclude: true,
+ priority: 50,
+ compile: log.fn('compile:regularTrans')
+ };
+ });
+ });
+ inject(function(log, $compile, $rootScope) {
+ $compile('
')($rootScope);
+ expect(log).toEqual('compile:elementTrans; compile:regularTrans; regular');
+ });
});
- });
- inject(function(log, $compile, $rootScope) {
- $compile('
')($rootScope);
- expect(log).toEqual('compile:elementTrans; compile:regularTrans; regular');
- });
- });
- it('should instantiate high priority controllers only once, but low priority ones each time we transclude',
- function() {
- module(function() {
- directive('elementTrans', function(log) {
- return {
- transclude: 'element',
- priority: 50,
- controller: function($transclude, $element) {
- log('controller:elementTrans');
- $transclude(function(clone) {
- $element.after(clone);
- });
- $transclude(function(clone) {
- $element.after(clone);
- });
- $transclude(function(clone) {
- $element.after(clone);
- });
- }
- };
+ it('should instantiate high priority controllers only once, but low priority ones each time we transclude',
+ function() {
+ module(function() {
+ directive('elementTrans', function(log) {
+ return {
+ transclude: 'element',
+ priority: 50,
+ controller: function($transclude, $element) {
+ log('controller:elementTrans');
+ $transclude(function(clone) {
+ $element.after(clone);
+ });
+ $transclude(function(clone) {
+ $element.after(clone);
+ });
+ $transclude(function(clone) {
+ $element.after(clone);
+ });
+ }
+ };
+ });
+ directive('normalDir', function(log) {
+ return {
+ controller: function() {
+ log('controller:normalDir');
+ }
+ };
+ });
+ });
+ inject(function($compile, $rootScope, log) {
+ element = $compile('
')($rootScope);
+ expect(log).toEqual([
+ 'controller:elementTrans',
+ 'controller:normalDir',
+ 'controller:normalDir',
+ 'controller:normalDir'
+ ]);
+ });
});
- directive('normalDir', function(log) {
- return {
- controller: function() {
- log('controller:normalDir');
- }
- };
+
+ it('should allow to access $transclude in the same directive', function() {
+ var _$transclude;
+ module(function() {
+ directive('transclude', valueFn({
+ transclude: 'element',
+ controller: function($transclude) {
+ _$transclude = $transclude;
+ }
+ }));
+ });
+ inject(function($compile) {
+ element = $compile('
')($rootScope);
+ expect(_$transclude).toBeDefined();
+ });
});
- });
- inject(function($compile, $rootScope, log) {
- element = $compile('
')($rootScope);
- expect(log).toEqual([
- 'controller:elementTrans',
- 'controller:normalDir',
- 'controller:normalDir',
- 'controller:normalDir'
- ]);
- });
- });
- it('should allow to access $transclude in the same directive', function() {
- var _$transclude;
- module(function() {
- directive('transclude', valueFn({
- transclude: 'element',
- controller: function($transclude) {
- _$transclude = $transclude;
- }
- }));
- });
- inject(function($compile) {
- element = $compile('
')($rootScope);
- expect(_$transclude).toBeDefined();
- });
- });
+ it('should copy the directive controller to all clones', function() {
+ var transcludeCtrl, cloneCount = 2;
+ module(function() {
+ directive('transclude', valueFn({
+ transclude: 'element',
+ controller: function() {
+ transcludeCtrl = this;
+ },
+ link: function(scope, el, attr, ctrl, $transclude) {
+ var i;
+ for (i = 0; i < cloneCount; i++) {
+ $transclude(cloneAttach);
+ }
- it('should copy the directive controller to all clones', function() {
- var transcludeCtrl, cloneCount = 2;
- module(function() {
- directive('transclude', valueFn({
- transclude: 'element',
- controller: function() {
- transcludeCtrl = this;
- },
- link: function(scope, el, attr, ctrl, $transclude) {
- var i;
+ function cloneAttach(clone) {
+ el.after(clone);
+ }
+ }
+ }));
+ });
+ inject(function($compile) {
+ element = $compile('
')($rootScope);
+ var children = element.children(), i;
for (i = 0; i < cloneCount; i++) {
- $transclude(cloneAttach);
+ expect(children.eq(i).data('$transcludeController')).toBe(transcludeCtrl);
}
+ });
+ });
- function cloneAttach(clone) {
- el.after(clone);
- }
- }
- }));
- });
- inject(function($compile) {
- element = $compile('
')($rootScope);
- var children = element.children(), i;
- for (i = 0; i < cloneCount; i++) {
- expect(children.eq(i).data('$transcludeController')).toBe(transcludeCtrl);
- }
- });
- });
+ it('should expose the directive controller to transcluded children', function() {
+ var capturedTranscludeCtrl;
+ module(function() {
+ directive('transclude', valueFn({
+ transclude: 'element',
+ controller: function() {
+ },
+ link: function(scope, element, attr, ctrl, $transclude) {
+ $transclude(scope, function(clone) {
+ element.after(clone);
+ });
+ }
+ }));
+ directive('child', valueFn({
+ require: '^transclude',
+ link: function(scope, element, attr, ctrl) {
+ capturedTranscludeCtrl = ctrl;
+ }
+ }));
+ });
+ inject(function($compile) {
+ // We need to wrap the transclude directive's element in a parent element so that the
+ // cloned element gets deallocated/cleaned up correctly
+ element = $compile('
')($rootScope);
+ expect(capturedTranscludeCtrl).toBeTruthy();
+ });
+ });
- it('should expose the directive controller to transcluded children', function() {
- var capturedTranscludeCtrl;
- module(function() {
- directive('transclude', valueFn({
- transclude: 'element',
- controller: function() {
- },
- link: function(scope, element, attr, ctrl, $transclude) {
- $transclude(scope, function(clone) {
- element.after(clone);
+ it('should allow access to $transclude in a templateUrl directive', function() {
+ var transclude;
+ module(function() {
+ directive('template', valueFn({
+ templateUrl: 'template.html',
+ replace: true
+ }));
+ directive('transclude', valueFn({
+ transclude: 'content',
+ controller: function($transclude) {
+ transclude = $transclude;
+ }
+ }));
+ });
+ inject(function($compile, $httpBackend) {
+ $httpBackend.expectGET('template.html').respond('
');
+ element = $compile('
')($rootScope);
+ $httpBackend.flush();
+ expect(transclude).toBeDefined();
+ });
+ });
+
+ // issue #6006
+ it('should link directive with $element as a comment node', function() {
+ module(function($provide) {
+ directive('innerAgain', function(log) {
+ return {
+ transclude: 'element',
+ link: function(scope, element, attr, controllers, transclude) {
+ log('innerAgain:' + lowercase(nodeName_(element)) + ':' + trim(element[0].data));
+ transclude(scope, function(clone) {
+ element.parent().append(clone);
+ });
+ }
+ };
+ });
+ directive('inner', function(log) {
+ return {
+ replace: true,
+ templateUrl: 'inner.html',
+ link: function(scope, element) {
+ log('inner:' + lowercase(nodeName_(element)) + ':' + trim(element[0].data));
+ }
+ };
});
- }
- }));
- directive('child', valueFn({
- require: '^transclude',
- link: function(scope, element, attr, ctrl) {
- capturedTranscludeCtrl = ctrl;
- }
- }));
- });
- inject(function($compile) {
- // We need to wrap the transclude directive's element in a parent element so that the
- // cloned element gets deallocated/cleaned up correctly
- element = $compile('
')($rootScope);
- expect(capturedTranscludeCtrl).toBeTruthy();
+ directive('outer', function(log) {
+ return {
+ transclude: 'element',
+ link: function(scope, element, attrs, controllers, transclude) {
+ log('outer:' + lowercase(nodeName_(element)) + ':' + trim(element[0].data));
+ transclude(scope, function(clone) {
+ element.parent().append(clone);
+ });
+ }
+ };
+ });
+ });
+ inject(function(log, $compile, $rootScope, $templateCache) {
+ $templateCache.put('inner.html', '
');
+ element = $compile('
')($rootScope);
+ $rootScope.$digest();
+ var child = element.children();
+
+ expect(log.toArray()).toEqual([
+ 'outer:#comment:outer:',
+ 'innerAgain:#comment:innerAgain:',
+ 'inner:#comment:innerAgain:'
+ ]);
+ expect(child.length).toBe(1);
+ expect(child.contents().length).toBe(2);
+ expect(lowercase(nodeName_(child.contents().eq(0)))).toBe('#comment');
+ expect(lowercase(nodeName_(child.contents().eq(1)))).toBe('div');
+ });
+ });
});
- });
- it('should allow access to $transclude in a templateUrl directive', function() {
- var transclude;
- module(function() {
- directive('template', valueFn({
- templateUrl: 'template.html',
- replace: true
- }));
- directive('transclude', valueFn({
- transclude: 'content',
- controller: function($transclude) {
- transclude = $transclude;
- }
- }));
- });
- inject(function($compile, $httpBackend) {
- $httpBackend.expectGET('template.html').respond('
');
- element = $compile('
')($rootScope);
- $httpBackend.flush();
- expect(transclude).toBeDefined();
- });
- });
- // issue #6006
- it('should link directive with $element as a comment node', function() {
- module(function($provide) {
- directive('innerAgain', function(log) {
- return {
- transclude: 'element',
- link: function(scope, element, attr, controllers, transclude) {
- log('innerAgain:' + lowercase(nodeName_(element)) + ':' + trim(element[0].data));
- transclude(scope, function(clone) {
- element.parent().append(clone);
- });
- }
- };
- });
- directive('inner', function(log) {
- return {
- replace: true,
- templateUrl: 'inner.html',
- link: function(scope, element) {
- log('inner:' + lowercase(nodeName_(element)) + ':' + trim(element[0].data));
- }
- };
+ it('should be possible to change the scope of a directive using $provide', function() {
+ module(function($provide) {
+ directive('foo', function() {
+ return {
+ scope: {},
+ template: '
'
+ };
+ });
+ $provide.decorator('fooDirective', function($delegate) {
+ var directive = $delegate[0];
+ directive.scope.something = '=';
+ directive.template = '
{{something}}';
+ return $delegate;
+ });
});
- directive('outer', function(log) {
- return {
- transclude: 'element',
- link: function(scope, element, attrs, controllers, transclude) {
- log('outer:' + lowercase(nodeName_(element)) + ':' + trim(element[0].data));
- transclude(scope, function(clone) {
- element.parent().append(clone);
- });
- }
- };
+ inject(function($compile, $rootScope) {
+ element = $compile('
')($rootScope);
+ $rootScope.bar = 'bar';
+ $rootScope.$digest();
+ expect(element.text()).toBe('bar');
});
});
- inject(function(log, $compile, $rootScope, $templateCache) {
- $templateCache.put('inner.html', '
');
- element = $compile('
')($rootScope);
- $rootScope.$digest();
- var child = element.children();
-
- expect(log.toArray()).toEqual([
- 'outer:#comment:outer:',
- 'innerAgain:#comment:innerAgain:',
- 'inner:#comment:innerAgain:'
- ]);
- expect(child.length).toBe(1);
- expect(child.contents().length).toBe(2);
- expect(lowercase(nodeName_(child.contents().eq(0)))).toBe('#comment');
- expect(lowercase(nodeName_(child.contents().eq(1)))).toBe('div');
- });
- });
- });
- it('should be possible to change the scope of a directive using $provide', function() {
- module(function($provide) {
- directive('foo', function() {
- return {
- scope: {},
- template: '
'
- };
- });
- $provide.decorator('fooDirective', function($delegate) {
- var directive = $delegate[0];
- directive.scope.something = '=';
- directive.template = '
{{something}}';
- return $delegate;
+ it('should distinguish different bindings with the same binding name', function() {
+ module(function() {
+ directive('foo', function() {
+ return {
+ scope: {
+ foo: '=',
+ bar: '='
+ },
+ template: '
'
+ };
+ });
+ });
+ inject(function($compile, $rootScope) {
+ element = $compile('
')($rootScope);
+ $rootScope.$digest();
+ expect(element.text()).toBe('foobar');
+ });
});
- });
- inject(function($compile, $rootScope) {
- element = $compile('
')($rootScope);
- $rootScope.bar = 'bar';
- $rootScope.$digest();
- expect(element.text()).toBe('bar');
- });
- });
-
- it('should distinguish different bindings with the same binding name', function() {
- module(function() {
- directive('foo', function() {
- return {
- scope: {
- foo: '=',
- bar: '='
- },
- template: '
'
- };
- });
- });
- inject(function($compile, $rootScope) {
- element = $compile('
')($rootScope);
- $rootScope.$digest();
- expect(element.text()).toBe('foobar');
- });
- });
+ it('should safely create transclude comment node and not break with "-->"',
+ inject(function($rootScope) {
+ // see: https://github.com/angular/angular.js/issues/1740
+ element = $compile('
')($rootScope);
+ $rootScope.$digest();
- it('should safely create transclude comment node and not break with "-->"',
- inject(function($rootScope) {
- // see: https://github.com/angular/angular.js/issues/1740
- element = $compile('
')($rootScope);
- $rootScope.$digest();
+ expect(element.text()).toBe('-->|x|');
+ }));
- expect(element.text()).toBe('-->|x|');
- }));
+ describe('lazy compilation', function() {
+ // See https://github.com/angular/angular.js/issues/7183
+ it('should pass transclusion through to template of a \'replace\' directive', function() {
+ module(function() {
+ directive('transSync', function() {
+ return {
+ transclude: true,
+ link: function(scope, element, attr, ctrl, transclude) {
- describe('lazy compilation', function() {
- // See https://github.com/angular/angular.js/issues/7183
- it('should pass transclusion through to template of a \'replace\' directive', function() {
- module(function() {
- directive('transSync', function() {
- return {
- transclude: true,
- link: function(scope, element, attr, ctrl, transclude) {
+ expect(transclude).toEqual(jasmine.any(Function));
- expect(transclude).toEqual(jasmine.any(Function));
+ transclude(function(child) { element.append(child); });
+ }
+ };
+ });
- transclude(function(child) { element.append(child); });
- }
- };
- });
+ directive('trans', function($timeout) {
+ return {
+ transclude: true,
+ link: function(scope, element, attrs, ctrl, transclude) {
- directive('trans', function($timeout) {
- return {
- transclude: true,
- link: function(scope, element, attrs, ctrl, transclude) {
+ // We use timeout here to simulate how ng-if works
+ $timeout(function() {
+ transclude(function(child) { element.append(child); });
+ });
+ }
+ };
+ });
- // We use timeout here to simulate how ng-if works
- $timeout(function() {
- transclude(function(child) { element.append(child); });
- });
- }
- };
- });
+ directive('replaceWithTemplate', function() {
+ return {
+ templateUrl: 'template.html',
+ replace: true
+ };
+ });
+ });
- directive('replaceWithTemplate', function() {
- return {
- templateUrl: 'template.html',
- replace: true
- };
- });
- });
+ inject(function($compile, $rootScope, $templateCache, $timeout) {
- inject(function($compile, $rootScope, $templateCache, $timeout) {
+ $templateCache.put('template.html', '
Content To Be Transcluded
');
- $templateCache.put('template.html', '
Content To Be Transcluded
');
+ expect(function() {
+ element = $compile('
')($rootScope);
+ $timeout.flush();
+ }).not.toThrow();
- expect(function() {
- element = $compile('
')($rootScope);
- $timeout.flush();
- }).not.toThrow();
+ expect(element.text()).toEqual('Content To Be Transcluded');
+ });
- expect(element.text()).toEqual('Content To Be Transcluded');
- });
+ });
- });
+ it('should lazily compile the contents of directives that are transcluded', function() {
+ var innerCompilationCount = 0, transclude;
- it('should lazily compile the contents of directives that are transcluded', function() {
- var innerCompilationCount = 0, transclude;
+ module(function() {
+ directive('trans', valueFn({
+ transclude: true,
+ controller: function($transclude) {
+ transclude = $transclude;
+ }
+ }));
- module(function() {
- directive('trans', valueFn({
- transclude: true,
- controller: function($transclude) {
- transclude = $transclude;
- }
- }));
+ directive('inner', valueFn({
+ template: '
FooBar',
+ compile: function() {
+ innerCompilationCount += 1;
+ }
+ }));
+ });
- directive('inner', valueFn({
- template: '
FooBar',
- compile: function() {
- innerCompilationCount += 1;
- }
- }));
- });
+ inject(function($compile, $rootScope) {
+ element = $compile('
')($rootScope);
+ expect(innerCompilationCount).toBe(0);
+ transclude(function(child) { element.append(child); });
+ expect(innerCompilationCount).toBe(1);
+ expect(element.text()).toBe('FooBar');
+ });
+ });
- inject(function($compile, $rootScope) {
- element = $compile('
')($rootScope);
- expect(innerCompilationCount).toBe(0);
- transclude(function(child) { element.append(child); });
- expect(innerCompilationCount).toBe(1);
- expect(element.text()).toBe('FooBar');
- });
- });
+ it('should lazily compile the contents of directives that are transcluded with a template', function() {
+ var innerCompilationCount = 0, transclude;
- it('should lazily compile the contents of directives that are transcluded with a template', function() {
- var innerCompilationCount = 0, transclude;
+ module(function() {
+ directive('trans', valueFn({
+ transclude: true,
+ template: '
Baz
',
+ controller: function($transclude) {
+ transclude = $transclude;
+ }
+ }));
- module(function() {
- directive('trans', valueFn({
- transclude: true,
- template: '
Baz
',
- controller: function($transclude) {
- transclude = $transclude;
- }
- }));
+ directive('inner', valueFn({
+ template: '
FooBar',
+ compile: function() {
+ innerCompilationCount += 1;
+ }
+ }));
+ });
- directive('inner', valueFn({
- template: '
FooBar',
- compile: function() {
- innerCompilationCount += 1;
- }
- }));
- });
+ inject(function($compile, $rootScope) {
+ element = $compile('
')($rootScope);
+ expect(innerCompilationCount).toBe(0);
+ transclude(function(child) { element.append(child); });
+ expect(innerCompilationCount).toBe(1);
+ expect(element.text()).toBe('BazFooBar');
+ });
+ });
- inject(function($compile, $rootScope) {
- element = $compile('
')($rootScope);
- expect(innerCompilationCount).toBe(0);
- transclude(function(child) { element.append(child); });
- expect(innerCompilationCount).toBe(1);
- expect(element.text()).toBe('BazFooBar');
- });
- });
+ it('should lazily compile the contents of directives that are transcluded with a templateUrl', function() {
+ var innerCompilationCount = 0, transclude;
- it('should lazily compile the contents of directives that are transcluded with a templateUrl', function() {
- var innerCompilationCount = 0, transclude;
+ module(function() {
+ directive('trans', valueFn({
+ transclude: true,
+ templateUrl: 'baz.html',
+ controller: function($transclude) {
+ transclude = $transclude;
+ }
+ }));
- module(function() {
- directive('trans', valueFn({
- transclude: true,
- templateUrl: 'baz.html',
- controller: function($transclude) {
- transclude = $transclude;
- }
- }));
+ directive('inner', valueFn({
+ template: '
FooBar',
+ compile: function() {
+ innerCompilationCount += 1;
+ }
+ }));
+ });
- directive('inner', valueFn({
- template: '
FooBar',
- compile: function() {
- innerCompilationCount += 1;
- }
- }));
- });
+ inject(function($compile, $rootScope, $httpBackend) {
+ $httpBackend.expectGET('baz.html').respond('
Baz
');
+ element = $compile('
')($rootScope);
+ $httpBackend.flush();
- inject(function($compile, $rootScope, $httpBackend) {
- $httpBackend.expectGET('baz.html').respond('
Baz
');
- element = $compile('
')($rootScope);
- $httpBackend.flush();
+ expect(innerCompilationCount).toBe(0);
+ transclude(function(child) { element.append(child); });
+ expect(innerCompilationCount).toBe(1);
+ expect(element.text()).toBe('BazFooBar');
+ });
+ });
- expect(innerCompilationCount).toBe(0);
- transclude(function(child) { element.append(child); });
- expect(innerCompilationCount).toBe(1);
- expect(element.text()).toBe('BazFooBar');
- });
- });
+ it('should lazily compile the contents of directives that are transclude element', function() {
+ var innerCompilationCount = 0, transclude;
- it('should lazily compile the contents of directives that are transclude element', function() {
- var innerCompilationCount = 0, transclude;
+ module(function() {
+ directive('trans', valueFn({
+ transclude: 'element',
+ controller: function($transclude) {
+ transclude = $transclude;
+ }
+ }));
- module(function() {
- directive('trans', valueFn({
- transclude: 'element',
- controller: function($transclude) {
- transclude = $transclude;
- }
- }));
+ directive('inner', valueFn({
+ template: '
FooBar',
+ compile: function() {
+ innerCompilationCount += 1;
+ }
+ }));
+ });
- directive('inner', valueFn({
- template: '
FooBar',
- compile: function() {
- innerCompilationCount += 1;
- }
- }));
- });
+ inject(function($compile, $rootScope) {
+ element = $compile('
')($rootScope);
+ expect(innerCompilationCount).toBe(0);
+ transclude(function(child) { element.append(child); });
+ expect(innerCompilationCount).toBe(1);
+ expect(element.text()).toBe('FooBar');
+ });
+ });
- inject(function($compile, $rootScope) {
- element = $compile('
')($rootScope);
- expect(innerCompilationCount).toBe(0);
- transclude(function(child) { element.append(child); });
- expect(innerCompilationCount).toBe(1);
- expect(element.text()).toBe('FooBar');
- });
- });
+ it('should lazily compile transcluded directives with ngIf on them', function() {
+ var innerCompilationCount = 0, outerCompilationCount = 0, transclude;
- it('should lazily compile transcluded directives with ngIf on them', function() {
- var innerCompilationCount = 0, outerCompilationCount = 0, transclude;
+ module(function() {
+ directive('outer', valueFn({
+ transclude: true,
+ compile: function() {
+ outerCompilationCount += 1;
+ },
+ controller: function($transclude) {
+ transclude = $transclude;
+ }
+ }));
- module(function() {
- directive('outer', valueFn({
- transclude: true,
- compile: function() {
- outerCompilationCount += 1;
- },
- controller: function($transclude) {
- transclude = $transclude;
- }
- }));
+ directive('inner', valueFn({
+ template: '
FooBar',
+ compile: function() {
+ innerCompilationCount += 1;
+ }
+ }));
+ });
- directive('inner', valueFn({
- template: '
FooBar',
- compile: function() {
- innerCompilationCount += 1;
- }
- }));
- });
+ inject(function($compile, $rootScope) {
+ $rootScope.shouldCompile = false;
+
+ element = $compile('
')($rootScope);
+ expect(outerCompilationCount).toBe(0);
+ expect(innerCompilationCount).toBe(0);
+ expect(transclude).toBeUndefined();
+ $rootScope.$apply('shouldCompile=true');
+ expect(outerCompilationCount).toBe(1);
+ expect(innerCompilationCount).toBe(0);
+ expect(transclude).toBeDefined();
+ transclude(function(child) { element.append(child); });
+ expect(outerCompilationCount).toBe(1);
+ expect(innerCompilationCount).toBe(1);
+ expect(element.text()).toBe('FooBar');
+ });
+ });
- inject(function($compile, $rootScope) {
- $rootScope.shouldCompile = false;
+ it('should eagerly compile multiple directives with transclusion and templateUrl/replace', function() {
+ var innerCompilationCount = 0;
- element = $compile('
')($rootScope);
- expect(outerCompilationCount).toBe(0);
- expect(innerCompilationCount).toBe(0);
- expect(transclude).toBeUndefined();
- $rootScope.$apply('shouldCompile=true');
- expect(outerCompilationCount).toBe(1);
- expect(innerCompilationCount).toBe(0);
- expect(transclude).toBeDefined();
- transclude(function(child) { element.append(child); });
- expect(outerCompilationCount).toBe(1);
- expect(innerCompilationCount).toBe(1);
- expect(element.text()).toBe('FooBar');
- });
- });
+ module(function() {
+ directive('outer', valueFn({
+ transclude: true
+ }));
- it('should eagerly compile multiple directives with transclusion and templateUrl/replace', function() {
- var innerCompilationCount = 0;
+ directive('outer', valueFn({
+ templateUrl: 'inner.html',
+ replace: true
+ }));
- module(function() {
- directive('outer', valueFn({
- transclude: true
- }));
+ directive('inner', valueFn({
+ compile: function() {
+ innerCompilationCount += 1;
+ }
+ }));
+ });
- directive('outer', valueFn({
- templateUrl: 'inner.html',
- replace: true
- }));
+ inject(function($compile, $rootScope, $httpBackend) {
+ $httpBackend.expectGET('inner.html').respond('
');
+ element = $compile('
')($rootScope);
+ $httpBackend.flush();
- directive('inner', valueFn({
- compile: function() {
- innerCompilationCount += 1;
- }
- }));
+ expect(innerCompilationCount).toBe(1);
+ });
+ });
});
- inject(function($compile, $rootScope, $httpBackend) {
- $httpBackend.expectGET('inner.html').respond('
');
- element = $compile('
')($rootScope);
- $httpBackend.flush();
-
- expect(innerCompilationCount).toBe(1);
- });
});
});
-
});
-
describe('multi-slot transclude', function() {
it('should only include elements without a matching transclusion element in default transclusion slot', function() {
module(function() {