aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Bosch2013-11-21 21:54:59 -0800
committerTobias Bosch2013-11-21 22:20:11 -0800
commite6521e7491242504250b57dd0ee66af49e653c33 (patch)
tree1a605bfc1a44c423ba7fec13ae94b984992bd0ab
parent0a7cbb33b06778833a4d99b1868cc07690a827a7 (diff)
downloadangular.js-e6521e7491242504250b57dd0ee66af49e653c33.tar.bz2
fix(ngView): Don't throw when the ngView element contains content with directives.
Fixes #5069
-rw-r--r--src/ngRoute/directive/ngView.js64
-rw-r--r--test/ngRoute/directive/ngViewSpec.js42
2 files changed, 72 insertions, 34 deletions
diff --git a/src/ngRoute/directive/ngView.js b/src/ngRoute/directive/ngView.js
index 3271ac0c..280bf423 100644
--- a/src/ngRoute/directive/ngView.js
+++ b/src/ngRoute/directive/ngView.js
@@ -199,37 +199,43 @@ function ngViewFactory( $route, $anchorScroll, $compile, $controller,
if (template) {
var newScope = scope.$new();
- $transclude(newScope, function(clone) {
- clone.html(template);
- $animate.enter(clone, null, currentElement || $element, function onNgViewEnter () {
- if (angular.isDefined(autoScrollExp)
- && (!autoScrollExp || scope.$eval(autoScrollExp))) {
- $anchorScroll();
- }
- });
-
- cleanupLastView();
-
- var link = $compile(clone.contents()),
- current = $route.current;
-
- currentScope = current.scope = newScope;
- currentElement = clone;
-
- 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.$eval(onloadExp);
+ // 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.
+ // However, using ng-view 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, angular.noop);
+ clone.html(template);
+ $animate.enter(clone, null, currentElement || $element, function onNgViewEnter () {
+ if (angular.isDefined(autoScrollExp)
+ && (!autoScrollExp || scope.$eval(autoScrollExp))) {
+ $anchorScroll();
+ }
});
+
+ cleanupLastView();
+
+ var link = $compile(clone.contents()),
+ current = $route.current;
+
+ currentScope = current.scope = newScope;
+ currentElement = clone;
+
+ 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.$eval(onloadExp);
} else {
cleanupLastView();
}
diff --git a/test/ngRoute/directive/ngViewSpec.js b/test/ngRoute/directive/ngViewSpec.js
index 533f0b53..f4b28058 100644
--- a/test/ngRoute/directive/ngViewSpec.js
+++ b/test/ngRoute/directive/ngViewSpec.js
@@ -515,12 +515,23 @@ describe('ngView', function() {
});
describe('ngView and transcludes', function() {
+ var element, directive;
+
+ beforeEach(module('ngRoute', function($compileProvider) {
+ element = null;
+ directive = $compileProvider.directive;
+ }));
+
+ afterEach(function() {
+ if (element) {
+ dealoc(element);
+ }
+ });
+
it('should allow access to directive controller from children when used in a replace template', function() {
var controller;
- module('ngRoute');
- module(function($compileProvider, $routeProvider) {
+ module(function($routeProvider) {
$routeProvider.when('/view', {templateUrl: 'view.html'});
- var directive = $compileProvider.directive;
directive('template', function() {
return {
template: '<div ng-view></div>',
@@ -542,14 +553,35 @@ describe('ngView and transcludes', function() {
});
inject(function($compile, $rootScope, $httpBackend, $location) {
$httpBackend.expectGET('view.html').respond('<div><div test></div></div>');
- var element = $compile('<div><div template></div></div>')($rootScope);
+ element = $compile('<div><div template></div></div>')($rootScope);
$location.url('/view');
$rootScope.$apply();
$httpBackend.flush();
expect(controller.flag).toBe(true);
- dealoc(element);
});
});
+
+ it("should compile it's content correctly (although we remove it later)", function() {
+ var testElement;
+ module(function($compileProvider, $routeProvider) {
+ $routeProvider.when('/view', {template: ' '});
+ var directive = $compileProvider.directive;
+ directive('test', function() {
+ return {
+ link: function(scope, element) {
+ testElement = element;
+ }
+ };
+ });
+ });
+ inject(function($compile, $rootScope, $location) {
+ element = $compile('<div><div ng-view><div test someAttr></div></div></div>')($rootScope);
+ $location.url('/view');
+ $rootScope.$apply();
+ expect(testElement[0].nodeName).toBe('DIV');
+ });
+
+ });
});
describe('ngView animations', function() {