diff --git a/src/ng/directive/ngInclude.js b/src/ng/directive/ngInclude.js index 90fd0b40ab40..f1c836f01a0c 100644 --- a/src/ng/directive/ngInclude.js +++ b/src/ng/directive/ngInclude.js @@ -15,8 +15,6 @@ * * @param {string} ng-include|src angular expression evaluating to URL. If the source is a string constant, * make sure you wrap it in quotes, e.g. `src="'myPartialTemplate.html'"`. - * @param {Scope=} [scope=new_child_scope] optional expression which evaluates to an - * instance of angular.module.ng.$rootScope.Scope to set the HTML fragment to. * @param {string=} onload Expression to evaluate when a new partial is loaded. * * @param {string=} autoscroll Whether `ng-include` should call {@link angular.module.ng.$anchorScroll @@ -78,8 +76,7 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile' return { restrict: 'EA', compile: function(element, attr) { - var srcExp = attr.ngInclude || attr.src, - scopeExp = attr.scope || '', + var srcExp = attr.ngInclude || attr.src, onloadExp = attr.onload || '', autoScrollExp = attr.autoscroll; @@ -87,45 +84,40 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile' var changeCounter = 0, childScope; - function incrementChange() { changeCounter++;} - scope.$watch(srcExp, incrementChange); - scope.$watch(function() { - var includeScope = scope.$eval(scopeExp); - if (includeScope) return includeScope.$id; - }, incrementChange); - scope.$watch(function() {return changeCounter;}, function(newChangeCounter) { - var src = scope.$eval(srcExp), - useScope = scope.$eval(scopeExp); + var clearContent = function() { + if (childScope) { + childScope.$destroy(); + childScope = null; + } + + element.html(''); + }; + + scope.$watch(srcExp, function(src) { + var thisChangeId = ++changeCounter; + + if (src) { + $http.get(src, {cache: $templateCache}).success(function(response) { + if (thisChangeId !== changeCounter) return; - function clearContent() { - // if this callback is still desired - if (newChangeCounter === changeCounter) { if (childScope) childScope.$destroy(); - childScope = null; - element.html(''); - } - } + childScope = scope.$new(); + + element.html(response); + $compile(element.contents())(childScope); + + if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) { + $anchorScroll(); + } - if (src) { - $http.get(src, {cache: $templateCache}).success(function(response) { - // if this callback is still desired - if (newChangeCounter === changeCounter) { - element.html(response); - if (childScope) childScope.$destroy(); - childScope = useScope ? useScope : scope.$new(); - $compile(element.contents())(childScope); - if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) { - $anchorScroll(); - } - scope.$emit('$includeContentLoaded'); - scope.$eval(onloadExp); - } - }).error(clearContent); - } else { - clearContent(); - } + scope.$emit('$includeContentLoaded'); + scope.$eval(onloadExp); + }).error(function() { + if (thisChangeId === changeCounter) clearContent(); + }); + } else clearContent(); }); }; } - } + }; }]; diff --git a/test/ng/directive/ngIncludeSpec.js b/test/ng/directive/ngIncludeSpec.js index ab63dd02a443..ae9454d6cec5 100644 --- a/test/ng/directive/ngIncludeSpec.js +++ b/test/ng/directive/ngIncludeSpec.js @@ -18,11 +18,10 @@ describe('ng-include', function() { it('should include on external file', inject(putIntoCache('myUrl', '{{name}}'), function($rootScope, $compile) { - element = jqLite(''); + element = jqLite(''); jqLite(document.body).append(element); element = $compile(element)($rootScope); - $rootScope.childScope = $rootScope.$new(); - $rootScope.childScope.name = 'misko'; + $rootScope.name = 'misko'; $rootScope.url = 'myUrl'; $rootScope.$digest(); expect(element.text()).toEqual('misko'); @@ -46,10 +45,9 @@ describe('ng-include', function() { it('should remove previously included text if a falsy value is bound to src', inject( putIntoCache('myUrl', '{{name}}'), function($rootScope, $compile) { - element = jqLite(''); + element = jqLite(''); element = $compile(element)($rootScope); - $rootScope.childScope = $rootScope.$new(); - $rootScope.childScope.name = 'igor'; + $rootScope.name = 'igor'; $rootScope.url = 'myUrl'; $rootScope.$digest(); @@ -62,23 +60,6 @@ describe('ng-include', function() { })); - it('should allow this for scope', inject(putIntoCache('myUrl', '{{"abc"}}'), - function($rootScope, $compile) { - element = jqLite(''); - element = $compile(element)($rootScope); - $rootScope.url = 'myUrl'; - $rootScope.$digest(); - - // TODO(misko): because we are using scope==this, the eval gets registered - // during the flush phase and hence does not get called. - // I don't think passing 'this' makes sense. Does having scope on ng-include makes sense? - // should we make scope="this" illegal? - $rootScope.$digest(); - - expect(element.text()).toEqual('abc'); - })); - - it('should fire $includeContentLoaded event after linking the content', inject( function($rootScope, $compile, $templateCache) { var contentLoadedSpy = jasmine.createSpy('content loaded').andCallFake(function() { @@ -111,20 +92,33 @@ describe('ng-include', function() { })); - it('should destroy old scope', inject(putIntoCache('myUrl', 'my partial'), - function($rootScope, $compile) { - element = jqLite(''); - element = $compile(element)($rootScope); + it('should create child scope and destroy old one', inject( + function($rootScope, $compile, $httpBackend) { + $httpBackend.whenGET('url1').respond('partial {{$parent.url}}'); + $httpBackend.whenGET('url2').respond(404); - expect($rootScope.$$childHead).toBeFalsy(); + element = $compile('')($rootScope); + expect(element.children().scope()).toBeFalsy(); - $rootScope.url = 'myUrl'; + $rootScope.url = 'url1'; + $rootScope.$digest(); + $httpBackend.flush(); + expect(element.children().scope()).toBeTruthy(); + expect(element.text()).toBe('partial url1'); + + $rootScope.url = 'url2'; + $rootScope.$digest(); + $httpBackend.flush(); + expect(element.children().scope()).toBeFalsy(); + expect(element.text()).toBe(''); + + $rootScope.url = 'url1'; $rootScope.$digest(); - expect($rootScope.$$childHead).toBeTruthy(); + expect(element.children().scope()).toBeTruthy(); $rootScope.url = null; $rootScope.$digest(); - expect($rootScope.$$childHead).toBeFalsy(); + expect(element.children().scope()).toBeFalsy(); }));