mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-05-02 12:14:45 +00:00
fix(ngView): 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 `ngView` are linked. Related to #5247.
This commit is contained in:
parent
43072e3812
commit
f8944efe70
2 changed files with 87 additions and 27 deletions
|
|
@ -1,6 +1,8 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
ngRouteModule.directive('ngView', ngViewFactory);
|
ngRouteModule.directive('ngView', ngViewFactory);
|
||||||
|
ngRouteModule.directive('ngView', ngViewFillContentFactory);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngdoc directive
|
* @ngdoc directive
|
||||||
|
|
@ -166,8 +168,8 @@ ngRouteModule.directive('ngView', ngViewFactory);
|
||||||
* @description
|
* @description
|
||||||
* Emitted every time the ngView content is reloaded.
|
* Emitted every time the ngView content is reloaded.
|
||||||
*/
|
*/
|
||||||
ngViewFactory.$inject = ['$route', '$anchorScroll', '$compile', '$controller', '$animate'];
|
ngViewFactory.$inject = ['$route', '$anchorScroll', '$animate'];
|
||||||
function ngViewFactory( $route, $anchorScroll, $compile, $controller, $animate) {
|
function ngViewFactory( $route, $anchorScroll, $animate) {
|
||||||
return {
|
return {
|
||||||
restrict: 'ECA',
|
restrict: 'ECA',
|
||||||
terminal: true,
|
terminal: true,
|
||||||
|
|
@ -199,6 +201,7 @@ function ngViewFactory( $route, $anchorScroll, $compile, $controller,
|
||||||
|
|
||||||
if (template) {
|
if (template) {
|
||||||
var newScope = scope.$new();
|
var newScope = scope.$new();
|
||||||
|
var current = $route.current;
|
||||||
|
|
||||||
// Note: This will also link all children of ng-view that were contained in the original
|
// Note: This will also link all children of ng-view 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.
|
||||||
|
|
@ -206,34 +209,18 @@ function ngViewFactory( $route, $anchorScroll, $compile, $controller,
|
||||||
// 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, angular.noop);
|
var clone = $transclude(newScope, function(clone) {
|
||||||
clone.html(template);
|
$animate.enter(clone, null, currentElement || $element, function onNgViewEnter () {
|
||||||
$animate.enter(clone, null, currentElement || $element, function onNgViewEnter () {
|
if (angular.isDefined(autoScrollExp)
|
||||||
if (angular.isDefined(autoScrollExp)
|
&& (!autoScrollExp || scope.$eval(autoScrollExp))) {
|
||||||
&& (!autoScrollExp || scope.$eval(autoScrollExp))) {
|
$anchorScroll();
|
||||||
$anchorScroll();
|
}
|
||||||
}
|
});
|
||||||
|
cleanupLastView();
|
||||||
});
|
});
|
||||||
|
|
||||||
cleanupLastView();
|
|
||||||
|
|
||||||
var link = $compile(clone.contents()),
|
|
||||||
current = $route.current;
|
|
||||||
|
|
||||||
currentScope = current.scope = newScope;
|
|
||||||
currentElement = clone;
|
currentElement = clone;
|
||||||
|
currentScope = current.scope = newScope;
|
||||||
if (current.controller) {
|
|
||||||
locals.$scope = currentScope;
|
|
||||||
var controller = $controller(current.controller, locals);
|
|
||||||
if (current.controllerAs) {
|
|
||||||
currentScope[current.controllerAs] = controller;
|
|
||||||
}
|
|
||||||
clone.data('$ngControllerController', controller);
|
|
||||||
clone.children().data('$ngControllerController', controller);
|
|
||||||
}
|
|
||||||
|
|
||||||
link(currentScope);
|
|
||||||
currentScope.$emit('$viewContentLoaded');
|
currentScope.$emit('$viewContentLoaded');
|
||||||
currentScope.$eval(onloadExp);
|
currentScope.$eval(onloadExp);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -243,3 +230,36 @@ function ngViewFactory( $route, $anchorScroll, $compile, $controller,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This directive is called during the $transclude call of the first `ngView` 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 ngView
|
||||||
|
// is called.
|
||||||
|
ngViewFillContentFactory.$inject = ['$compile', '$controller', '$route'];
|
||||||
|
function ngViewFillContentFactory($compile, $controller, $route) {
|
||||||
|
return {
|
||||||
|
restrict: 'ECA',
|
||||||
|
priority: -400,
|
||||||
|
link: function(scope, $element) {
|
||||||
|
var current = $route.current,
|
||||||
|
locals = current.locals;
|
||||||
|
|
||||||
|
$element.html(locals.$template);
|
||||||
|
|
||||||
|
var link = $compile($element.contents());
|
||||||
|
|
||||||
|
if (current.controller) {
|
||||||
|
locals.$scope = scope;
|
||||||
|
var controller = $controller(current.controller, locals);
|
||||||
|
if (current.controllerAs) {
|
||||||
|
scope[current.controllerAs] = controller;
|
||||||
|
}
|
||||||
|
$element.data('$ngControllerController', controller);
|
||||||
|
$element.children().data('$ngControllerController', controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
link(scope);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -582,6 +582,46 @@ describe('ngView and transcludes', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should link directives on the same element after the content has been loaded', function() {
|
||||||
|
var contentOnLink;
|
||||||
|
module(function($compileProvider, $routeProvider) {
|
||||||
|
$routeProvider.when('/view', {template: 'someContent'});
|
||||||
|
$compileProvider.directive('test', function() {
|
||||||
|
return {
|
||||||
|
link: function(scope, element) {
|
||||||
|
contentOnLink = element.text();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
inject(function($compile, $rootScope, $location) {
|
||||||
|
element = $compile('<div><div ng-view test></div>')($rootScope);
|
||||||
|
$location.url('/view');
|
||||||
|
$rootScope.$apply();
|
||||||
|
expect(contentOnLink).toBe('someContent');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add the content to the element before compiling it', function() {
|
||||||
|
var root;
|
||||||
|
module(function($compileProvider, $routeProvider) {
|
||||||
|
$routeProvider.when('/view', {template: '<span test></span>'});
|
||||||
|
$compileProvider.directive('test', function() {
|
||||||
|
return {
|
||||||
|
link: function(scope, element) {
|
||||||
|
root = element.parent().parent();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
inject(function($compile, $rootScope, $location) {
|
||||||
|
element = $compile('<div><div ng-view></div>')($rootScope);
|
||||||
|
$location.url('/view');
|
||||||
|
$rootScope.$apply();
|
||||||
|
expect(root[0]).toBe(element[0]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('ngView animations', function() {
|
describe('ngView animations', function() {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue