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

Commit

Permalink
fix(ngInclude): Add template to DOM before linking other directives
Browse files Browse the repository at this point in the history
The template needs to be added to the DOM before
other directives at the same element as `ngInclude` are linked.

Fixes #5247.
  • Loading branch information
tbosch committed Dec 13, 2013
1 parent f8944ef commit 30a8b7d
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 7 deletions.
4 changes: 4 additions & 0 deletions src/AngularPublic.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
ngHideDirective,
ngIfDirective,
ngIncludeDirective,
ngIncludeFillContentDirective,
ngInitDirective,
ngNonBindableDirective,
ngPluralizeDirective,
Expand Down Expand Up @@ -181,6 +182,9 @@ function publishExternalAPI(angular){
ngRequired: requiredDirective,
ngValue: ngValueDirective
}).
directive({
ngInclude: ngIncludeFillContentDirective
}).
directive(ngAttributeAliasDirectives).
directive(ngEventDirectives);
$provide.provider({
Expand Down
34 changes: 27 additions & 7 deletions src/ng/directive/ngInclude.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,14 @@
* @description
* Emitted every time the ngInclude content is reloaded.
*/
var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile', '$animate', '$sce',
function($http, $templateCache, $anchorScroll, $compile, $animate, $sce) {
var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate', '$sce',
function($http, $templateCache, $anchorScroll, $animate, $sce) {
return {
restrict: 'ECA',
priority: 400,
terminal: true,
transclude: 'element',
controller: angular.noop,
compile: function(element, attr) {
var srcExp = attr.ngInclude || attr.src,
onloadExp = attr.onload || '',
Expand Down Expand Up @@ -187,22 +188,22 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
$http.get(src, {cache: $templateCache}).success(function(response) {
if (thisChangeId !== changeCounter) return;
var newScope = scope.$new();
ctrl.template = response;

// Note: This will also link all children of ng-include that were contained in the original
// html. If that content contains controllers, ... they could pollute/change the scope.
// However, using ng-include on an element with additional content does not make sense...
// Note: We can't remove them in the cloneAttchFn of $transclude as that
// function is called before linking the content, which would apply child
// directives to non existing elements.
var clone = $transclude(newScope, noop);
cleanupLastIncludeContent();
var clone = $transclude(newScope, function(clone) {
cleanupLastIncludeContent();
$animate.enter(clone, null, $element, afterAnimation);
});

currentScope = newScope;
currentElement = clone;

currentElement.html(response);
$animate.enter(currentElement, null, $element, afterAnimation);
$compile(currentElement.contents())(currentScope);
currentScope.$emit('$includeContentLoaded');
scope.$eval(onloadExp);
}).error(function() {
Expand All @@ -211,9 +212,28 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
scope.$emit('$includeContentRequested');
} else {
cleanupLastIncludeContent();
ctrl.template = null;
}
});
};
}
};
}];

// This directive is called during the $transclude call of the first `ngInclude` directive.
// It will replace and compile the content of the element with the loaded template.
// We need this directive so that the element content is already filled when
// the link function of another directive on the same element as ngInclude
// is called.
var ngIncludeFillContentDirective = ['$compile',
function($compile) {
return {
restrict: 'ECA',
priority: -400,
require: 'ngInclude',
link: function(scope, $element, $attr, ctrl) {
$element.html(ctrl.template);
$compile($element.contents())(scope);
}
};
}];
40 changes: 40 additions & 0 deletions test/ng/directive/ngIncludeSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,46 @@ describe('ngInclude and transcludes', function() {
});

});

it('should link directives on the same element after the content has been loaded', function() {
var contentOnLink;
module(function() {
directive('test', function() {
return {
link: function(scope, element) {
contentOnLink = element.text();
}
};
});
});
inject(function($compile, $rootScope, $httpBackend) {
$httpBackend.expectGET('include.html').respond('someContent');
element = $compile('<div><div ng-include="\'include.html\'" test></div>')($rootScope);
$rootScope.$apply();
$httpBackend.flush();
expect(contentOnLink).toBe('someContent');
});
});

it('should add the content to the element before compiling it', function() {
var root;
module(function() {
directive('test', function() {
return {
link: function(scope, element) {
root = element.parent().parent();
}
};
});
});
inject(function($compile, $rootScope, $httpBackend) {
$httpBackend.expectGET('include.html').respond('<span test></span>');
element = $compile('<div><div ng-include="\'include.html\'"></div>')($rootScope);
$rootScope.$apply();
$httpBackend.flush();
expect(root[0]).toBe(element[0]);
});
});
});

describe('ngInclude animations', function() {
Expand Down

0 comments on commit 30a8b7d

Please sign in to comment.