mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-25 18:50:26 +00:00
refactor(ngInclude): remove scope attribute
The purpose of allowing the scope to be specified was to enable the $route service to work together with ngInclude. However the functionality of creating scopes was in the recent past moved from the $route service to the ngView directive, so currently there is no valid use case for specifying the scope for ngInclude. In fact, allowing the scope to be defined can under certain circumstances lead to memory leaks. Breaks ngInclude does not have scope attribute anymore.
This commit is contained in:
parent
06d0955074
commit
5f70d615a5
2 changed files with 57 additions and 71 deletions
|
|
@ -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);
|
||||
|
||||
function clearContent() {
|
||||
// if this callback is still desired
|
||||
if (newChangeCounter === changeCounter) {
|
||||
if (childScope) childScope.$destroy();
|
||||
childScope = null;
|
||||
element.html('');
|
||||
}
|
||||
var clearContent = function() {
|
||||
if (childScope) {
|
||||
childScope.$destroy();
|
||||
childScope = null;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
element.html('');
|
||||
};
|
||||
|
||||
scope.$watch(srcExp, function(src) {
|
||||
var thisChangeId = ++changeCounter;
|
||||
|
||||
if (src) {
|
||||
$http.get(src, {cache: $templateCache}).success(function(response) {
|
||||
if (thisChangeId !== changeCounter) return;
|
||||
|
||||
if (childScope) childScope.$destroy();
|
||||
childScope = scope.$new();
|
||||
|
||||
element.html(response);
|
||||
$compile(element.contents())(childScope);
|
||||
|
||||
if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
|
||||
$anchorScroll();
|
||||
}
|
||||
|
||||
scope.$emit('$includeContentLoaded');
|
||||
scope.$eval(onloadExp);
|
||||
}).error(function() {
|
||||
if (thisChangeId === changeCounter) clearContent();
|
||||
});
|
||||
} else clearContent();
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
}];
|
||||
|
|
|
|||
|
|
@ -18,11 +18,10 @@ describe('ng-include', function() {
|
|||
|
||||
it('should include on external file', inject(putIntoCache('myUrl', '{{name}}'),
|
||||
function($rootScope, $compile) {
|
||||
element = jqLite('<ng:include src="url" scope="childScope"></ng:include>');
|
||||
element = jqLite('<ng:include src="url"></ng:include>');
|
||||
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('<ng:include src="url" scope="childScope"></ng:include>');
|
||||
element = jqLite('<ng:include src="url"></ng:include>');
|
||||
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('<ng:include src="url" scope="this"></ng:include>');
|
||||
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('<ng:include src="url"></ng:include>');
|
||||
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('<ng:include src="url"></ng:include>')($rootScope);
|
||||
expect(element.children().scope()).toBeFalsy();
|
||||
|
||||
$rootScope.url = 'myUrl';
|
||||
$rootScope.url = 'url1';
|
||||
$rootScope.$digest();
|
||||
expect($rootScope.$$childHead).toBeTruthy();
|
||||
$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(element.children().scope()).toBeTruthy();
|
||||
|
||||
$rootScope.url = null;
|
||||
$rootScope.$digest();
|
||||
expect($rootScope.$$childHead).toBeFalsy();
|
||||
expect(element.children().scope()).toBeFalsy();
|
||||
}));
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue