mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-17 07:40:22 +00:00
fix(ngInclude): Add template to DOM before linking other directives
The template needs to be added to the DOM before other directives at the same element as `ngInclude` are linked. Fixes #5247.
This commit is contained in:
parent
f8944efe70
commit
30a8b7d0b5
3 changed files with 71 additions and 7 deletions
|
|
@ -28,6 +28,7 @@
|
|||
ngHideDirective,
|
||||
ngIfDirective,
|
||||
ngIncludeDirective,
|
||||
ngIncludeFillContentDirective,
|
||||
ngInitDirective,
|
||||
ngNonBindableDirective,
|
||||
ngPluralizeDirective,
|
||||
|
|
@ -181,6 +182,9 @@ function publishExternalAPI(angular){
|
|||
ngRequired: requiredDirective,
|
||||
ngValue: ngValueDirective
|
||||
}).
|
||||
directive({
|
||||
ngInclude: ngIncludeFillContentDirective
|
||||
}).
|
||||
directive(ngAttributeAliasDirectives).
|
||||
directive(ngEventDirectives);
|
||||
$provide.provider({
|
||||
|
|
|
|||
|
|
@ -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 || '',
|
||||
|
|
@ -187,6 +188,7 @@ 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.
|
||||
|
|
@ -194,15 +196,14 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
|
|||
// 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() {
|
||||
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}];
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue