mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-05-17 11:11:05 +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,
|
ngHideDirective,
|
||||||
ngIfDirective,
|
ngIfDirective,
|
||||||
ngIncludeDirective,
|
ngIncludeDirective,
|
||||||
|
ngIncludeFillContentDirective,
|
||||||
ngInitDirective,
|
ngInitDirective,
|
||||||
ngNonBindableDirective,
|
ngNonBindableDirective,
|
||||||
ngPluralizeDirective,
|
ngPluralizeDirective,
|
||||||
|
|
@ -181,6 +182,9 @@ function publishExternalAPI(angular){
|
||||||
ngRequired: requiredDirective,
|
ngRequired: requiredDirective,
|
||||||
ngValue: ngValueDirective
|
ngValue: ngValueDirective
|
||||||
}).
|
}).
|
||||||
|
directive({
|
||||||
|
ngInclude: ngIncludeFillContentDirective
|
||||||
|
}).
|
||||||
directive(ngAttributeAliasDirectives).
|
directive(ngAttributeAliasDirectives).
|
||||||
directive(ngEventDirectives);
|
directive(ngEventDirectives);
|
||||||
$provide.provider({
|
$provide.provider({
|
||||||
|
|
|
||||||
|
|
@ -147,13 +147,14 @@
|
||||||
* @description
|
* @description
|
||||||
* Emitted every time the ngInclude content is reloaded.
|
* Emitted every time the ngInclude content is reloaded.
|
||||||
*/
|
*/
|
||||||
var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile', '$animate', '$sce',
|
var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate', '$sce',
|
||||||
function($http, $templateCache, $anchorScroll, $compile, $animate, $sce) {
|
function($http, $templateCache, $anchorScroll, $animate, $sce) {
|
||||||
return {
|
return {
|
||||||
restrict: 'ECA',
|
restrict: 'ECA',
|
||||||
priority: 400,
|
priority: 400,
|
||||||
terminal: true,
|
terminal: true,
|
||||||
transclude: 'element',
|
transclude: 'element',
|
||||||
|
controller: angular.noop,
|
||||||
compile: function(element, attr) {
|
compile: function(element, attr) {
|
||||||
var srcExp = attr.ngInclude || attr.src,
|
var srcExp = attr.ngInclude || attr.src,
|
||||||
onloadExp = attr.onload || '',
|
onloadExp = attr.onload || '',
|
||||||
|
|
@ -187,6 +188,7 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
|
||||||
$http.get(src, {cache: $templateCache}).success(function(response) {
|
$http.get(src, {cache: $templateCache}).success(function(response) {
|
||||||
if (thisChangeId !== changeCounter) return;
|
if (thisChangeId !== changeCounter) return;
|
||||||
var newScope = scope.$new();
|
var newScope = scope.$new();
|
||||||
|
ctrl.template = response;
|
||||||
|
|
||||||
// Note: This will also link all children of ng-include that were contained in the original
|
// 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.
|
// 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
|
// Note: We can't remove them in the cloneAttchFn of $transclude as that
|
||||||
// function is called before linking the content, which would apply child
|
// function is called before linking the content, which would apply child
|
||||||
// directives to non existing elements.
|
// directives to non existing elements.
|
||||||
var clone = $transclude(newScope, noop);
|
var clone = $transclude(newScope, function(clone) {
|
||||||
cleanupLastIncludeContent();
|
cleanupLastIncludeContent();
|
||||||
|
$animate.enter(clone, null, $element, afterAnimation);
|
||||||
|
});
|
||||||
|
|
||||||
currentScope = newScope;
|
currentScope = newScope;
|
||||||
currentElement = clone;
|
currentElement = clone;
|
||||||
|
|
||||||
currentElement.html(response);
|
|
||||||
$animate.enter(currentElement, null, $element, afterAnimation);
|
|
||||||
$compile(currentElement.contents())(currentScope);
|
|
||||||
currentScope.$emit('$includeContentLoaded');
|
currentScope.$emit('$includeContentLoaded');
|
||||||
scope.$eval(onloadExp);
|
scope.$eval(onloadExp);
|
||||||
}).error(function() {
|
}).error(function() {
|
||||||
|
|
@ -211,9 +212,28 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
|
||||||
scope.$emit('$includeContentRequested');
|
scope.$emit('$includeContentRequested');
|
||||||
} else {
|
} else {
|
||||||
cleanupLastIncludeContent();
|
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() {
|
describe('ngInclude animations', function() {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue