refactor(ng:view, ng:include): pass cache instance into $http

Instead of doing all the stuff in these widgets (checking cache, etc..) we can rely on $http now...
This commit is contained in:
Vojta Jina 2011-11-04 18:33:12 -07:00 committed by Igor Minar
parent 92995bbce9
commit 16363d8000
2 changed files with 63 additions and 62 deletions

View file

@ -112,18 +112,6 @@ angularWidget('ng:include', function(element){
useScope = scope.$eval(scopeExp), useScope = scope.$eval(scopeExp),
fromCache; fromCache;
function updateContent(content) {
element.html(content);
if (useScope) {
childScope = useScope;
} else {
releaseScopes.push(childScope = scope.$new());
}
compiler.compile(element)(childScope);
$autoScroll();
scope.$eval(onloadExp);
}
function clearContent() { function clearContent() {
childScope = null; childScope = null;
element.html(''); element.html('');
@ -133,16 +121,17 @@ angularWidget('ng:include', function(element){
releaseScopes.pop().$destroy(); releaseScopes.pop().$destroy();
} }
if (src) { if (src) {
if ((fromCache = $templateCache.get(src))) { $http.get(src, {cache: $templateCache}).on('success', function(response) {
scope.$evalAsync(function() { element.html(response);
updateContent(fromCache); if (useScope) {
}); childScope = useScope;
} else { } else {
$http.get(src).on('success', function(response) { releaseScopes.push(childScope = scope.$new());
updateContent(response); }
$templateCache.put(src, response); compiler.compile(element)(childScope);
}).on('error', clearContent); $autoScroll();
} scope.$eval(onloadExp);
}).on('error', clearContent);
} else { } else {
clearContent(); clearContent();
} }
@ -586,30 +575,20 @@ angularWidget('ng:view', function(element) {
var template = $route.current && $route.current.template, var template = $route.current && $route.current.template,
fromCache; fromCache;
function updateContent(content) {
element.html(content);
compiler.compile(element)($route.current.scope);
}
function clearContent() { function clearContent() {
element.html(''); element.html('');
} }
if (template) { if (template) {
if ((fromCache = $templateCache.get(template))) { // xhr's callback must be async, see commit history for more info
scope.$evalAsync(function() { $http.get(template, {cache: $templateCache}).on('success', function(response) {
updateContent(fromCache); // ignore callback if another route change occured since
}); if (newChangeCounter == changeCounter) {
} else { element.html(response);
// xhr's callback must be async, see commit history for more info compiler.compile(element)($route.current.scope);
$http.get(template).on('success', function(response) {
// ignore callback if another route change occured since
if (newChangeCounter == changeCounter)
updateContent(response);
$templateCache.put(template, response);
$autoScroll(); $autoScroll();
}).on('error', clearContent); }
} }).on('error', clearContent);
} else { } else {
clearContent(); clearContent();
} }

View file

@ -56,27 +56,37 @@ describe("widget", function() {
describe('ng:include', inject(function($rootScope, $compile) { describe('ng:include', inject(function($rootScope, $compile) {
it('should include on external file', inject(function($rootScope, $compile, $cacheFactory) {
function putIntoCache(url, content) {
return function($templateCache) {
$templateCache.put(url, [200, content, {}]);
};
}
it('should include on external file', inject(putIntoCache('myUrl', '{{name}}'),
function($rootScope, $compile, $browser) {
var element = jqLite('<ng:include src="url" scope="childScope"></ng:include>'); var element = jqLite('<ng:include src="url" scope="childScope"></ng:include>');
var element = $compile(element)($rootScope); var element = $compile(element)($rootScope);
$rootScope.childScope = $rootScope.$new(); $rootScope.childScope = $rootScope.$new();
$rootScope.childScope.name = 'misko'; $rootScope.childScope.name = 'misko';
$rootScope.url = 'myUrl'; $rootScope.url = 'myUrl';
$cacheFactory.get('templates').put('myUrl', '{{name}}');
$rootScope.$digest(); $rootScope.$digest();
$browser.defer.flush();
expect(element.text()).toEqual('misko'); expect(element.text()).toEqual('misko');
})); }));
it('should remove previously included text if a falsy value is bound to src', it('should remove previously included text if a falsy value is bound to src', inject(
inject(function($rootScope, $compile, $cacheFactory) { putIntoCache('myUrl', '{{name}}'),
function($rootScope, $compile, $browser) {
var element = jqLite('<ng:include src="url" scope="childScope"></ng:include>'); var element = jqLite('<ng:include src="url" scope="childScope"></ng:include>');
var element = $compile(element)($rootScope); var element = $compile(element)($rootScope);
$rootScope.childScope = $rootScope.$new(); $rootScope.childScope = $rootScope.$new();
$rootScope.childScope.name = 'igor'; $rootScope.childScope.name = 'igor';
$rootScope.url = 'myUrl'; $rootScope.url = 'myUrl';
$cacheFactory.get('templates').put('myUrl', '{{name}}');
$rootScope.$digest(); $rootScope.$digest();
$browser.defer.flush();
expect(element.text()).toEqual('igor'); expect(element.text()).toEqual('igor');
@ -86,13 +96,15 @@ describe("widget", function() {
expect(element.text()).toEqual(''); expect(element.text()).toEqual('');
})); }));
it('should allow this for scope', inject(function($rootScope, $compile, $cacheFactory) { it('should allow this for scope', inject(putIntoCache('myUrl', '{{"abc"}}'),
function($rootScope, $compile, $browser) {
var element = jqLite('<ng:include src="url" scope="this"></ng:include>'); var element = jqLite('<ng:include src="url" scope="this"></ng:include>');
var element = $compile(element)($rootScope); var element = $compile(element)($rootScope);
$rootScope.url = 'myUrl'; $rootScope.url = 'myUrl';
$cacheFactory.get('templates').put('myUrl', '{{"abc"}}');
$rootScope.$digest(); $rootScope.$digest();
$browser.defer.flush();
// TODO(misko): because we are using scope==this, the eval gets registered // TODO(misko): because we are using scope==this, the eval gets registered
// during the flush phase and hence does not get called. // 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? // I don't think passing 'this' makes sense. Does having scope on ng:include makes sense?
@ -102,31 +114,34 @@ describe("widget", function() {
expect(element.text()).toEqual('abc'); expect(element.text()).toEqual('abc');
})); }));
it('should evaluate onload expression when a partial is loaded', it('should evaluate onload expression when a partial is loaded', inject(
inject(function($rootScope, $compile, $cacheFactory) { putIntoCache('myUrl', 'my partial'),
function($rootScope, $compile, $browser) {
var element = jqLite('<ng:include src="url" onload="loaded = true"></ng:include>'); var element = jqLite('<ng:include src="url" onload="loaded = true"></ng:include>');
var element = $compile(element)($rootScope); var element = $compile(element)($rootScope);
expect($rootScope.loaded).not.toBeDefined(); expect($rootScope.loaded).not.toBeDefined();
$rootScope.url = 'myUrl'; $rootScope.url = 'myUrl';
$cacheFactory.get('templates').put('myUrl', 'my partial');
$rootScope.$digest(); $rootScope.$digest();
$browser.defer.flush();
expect(element.text()).toEqual('my partial'); expect(element.text()).toEqual('my partial');
expect($rootScope.loaded).toBe(true); expect($rootScope.loaded).toBe(true);
})); }));
it('should destroy old scope', inject(function($rootScope, $compile, $cacheFactory) { it('should destroy old scope', inject(putIntoCache('myUrl', 'my partial'),
function($rootScope, $compile, $browser) {
var element = jqLite('<ng:include src="url"></ng:include>'); var element = jqLite('<ng:include src="url"></ng:include>');
var element = $compile(element)($rootScope); var element = $compile(element)($rootScope);
expect($rootScope.$$childHead).toBeFalsy(); expect($rootScope.$$childHead).toBeFalsy();
$rootScope.url = 'myUrl'; $rootScope.url = 'myUrl';
$cacheFactory.get('templates').put('myUrl', 'my partial');
$rootScope.$digest(); $rootScope.$digest();
$browser.defer.flush();
expect($rootScope.$$childHead).toBeTruthy(); expect($rootScope.$$childHead).toBeTruthy();
$rootScope.url = null; $rootScope.url = null;
@ -134,7 +149,8 @@ describe("widget", function() {
expect($rootScope.$$childHead).toBeFalsy(); expect($rootScope.$$childHead).toBeFalsy();
})); }));
it('should do xhr request and cache it', inject(function($rootScope, $httpBackend, $compile) { it('should do xhr request and cache it',
inject(function($rootScope, $httpBackend, $compile, $browser) {
var element = $compile('<ng:include src="url"></ng:include>')($rootScope); var element = $compile('<ng:include src="url"></ng:include>')($rootScope);
$httpBackend.expect('GET', 'myUrl').respond('my partial'); $httpBackend.expect('GET', 'myUrl').respond('my partial');
@ -149,6 +165,7 @@ describe("widget", function() {
$rootScope.url = 'myUrl'; $rootScope.url = 'myUrl';
$rootScope.$digest(); $rootScope.$digest();
$browser.defer.flush();
expect(element.text()).toEqual('my partial'); expect(element.text()).toEqual('my partial');
dealoc($rootScope); dealoc($rootScope);
})); }));
@ -165,11 +182,12 @@ describe("widget", function() {
expect(element.text()).toBe(''); expect(element.text()).toBe('');
})); }));
it('should be async even if served from cache', inject(function($rootScope, $compile, $cacheFactory) { it('should be async even if served from cache', inject(
putIntoCache('myUrl', 'my partial'),
function($rootScope, $compile, $browser) {
var element = $compile('<ng:include src="url"></ng:include>')($rootScope); var element = $compile('<ng:include src="url"></ng:include>')($rootScope);
$rootScope.url = 'myUrl'; $rootScope.url = 'myUrl';
$cacheFactory.get('templates').put('myUrl', 'my partial');
var called = 0; var called = 0;
// we want to assert only during first watch // we want to assert only during first watch
@ -178,6 +196,7 @@ describe("widget", function() {
}); });
$rootScope.$digest(); $rootScope.$digest();
$browser.defer.flush();
expect(element.text()).toBe('my partial'); expect(element.text()).toBe('my partial');
})); }));
})); }));
@ -574,7 +593,8 @@ describe("widget", function() {
})); }));
it('should initialize view template after the view controller was initialized even when ' + it('should initialize view template after the view controller was initialized even when ' +
'templates were cached', inject(function($rootScope, $compile, $location, $httpBackend, $route) { 'templates were cached',
inject(function($rootScope, $compile, $location, $httpBackend, $route, $browser) {
//this is a test for a regression that was introduced by making the ng:view cache sync //this is a test for a regression that was introduced by making the ng:view cache sync
$route.when('/foo', {controller: ParentCtrl, template: 'viewPartial.html'}); $route.when('/foo', {controller: ParentCtrl, template: 'viewPartial.html'});
@ -605,6 +625,7 @@ describe("widget", function() {
$rootScope.log = []; $rootScope.log = [];
$location.path('/foo'); $location.path('/foo');
$rootScope.$apply(); $rootScope.$apply();
$browser.defer.flush();
expect($rootScope.log).toEqual(['parent', 'init', 'child']); expect($rootScope.log).toEqual(['parent', 'init', 'child']);
})); }));
@ -644,9 +665,9 @@ describe("widget", function() {
})); }));
it('should be async even if served from cache', it('should be async even if served from cache',
inject(function($route, $rootScope, $location, $cacheFactory) { inject(function($route, $rootScope, $location, $templateCache, $browser) {
$templateCache.put('myUrl1', [200, 'my partial', {}]);
$route.when('/foo', {controller: noop, template: 'myUrl1'}); $route.when('/foo', {controller: noop, template: 'myUrl1'});
$cacheFactory.get('templates').put('myUrl1', 'my partial');
$location.path('/foo'); $location.path('/foo');
var called = 0; var called = 0;
@ -656,6 +677,7 @@ describe("widget", function() {
}); });
$rootScope.$digest(); $rootScope.$digest();
$browser.defer.flush();
expect(element.text()).toBe('my partial'); expect(element.text()).toBe('my partial');
})); }));
}); });