Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b3c6c26

Browse files
committedAug 12, 2014
refactor($compile): use $$templateRequest for downloading and caching template requests
1 parent 2d678f1 commit b3c6c26

File tree

9 files changed

+163
-36
lines changed

9 files changed

+163
-36
lines changed
 

‎angularFiles.js

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ var angularFiles = {
3434
'src/ng/sanitizeUri.js',
3535
'src/ng/sce.js',
3636
'src/ng/sniffer.js',
37+
'src/ng/templateRequest.js',
3738
'src/ng/timeout.js',
3839
'src/ng/urlUtils.js',
3940
'src/ng/window.js',

‎src/AngularPublic.js

+2
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
$SceDelegateProvider,
7979
$SnifferProvider,
8080
$TemplateCacheProvider,
81+
$$TemplateRequestProvider,
8182
$TimeoutProvider,
8283
$$RAFProvider,
8384
$$AsyncCallbackProvider,
@@ -227,6 +228,7 @@ function publishExternalAPI(angular){
227228
$sceDelegate: $SceDelegateProvider,
228229
$sniffer: $SnifferProvider,
229230
$templateCache: $TemplateCacheProvider,
231+
$$templateRequest: $$TemplateRequestProvider,
230232
$timeout: $TimeoutProvider,
231233
$window: $WindowProvider,
232234
$$rAF: $$RAFProvider,

‎src/ng/compile.js

+4-7
Original file line numberDiff line numberDiff line change
@@ -658,9 +658,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
658658
};
659659

660660
this.$get = [
661-
'$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
661+
'$injector', '$interpolate', '$exceptionHandler', '$$templateRequest', '$parse',
662662
'$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
663-
function($injector, $interpolate, $exceptionHandler, $http, $templateCache, $parse,
663+
function($injector, $interpolate, $exceptionHandler, $$templateRequest, $parse,
664664
$controller, $rootScope, $document, $sce, $animate, $$sanitizeUri) {
665665

666666
var Attributes = function(element, attr) {
@@ -1756,8 +1756,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
17561756

17571757
$compileNode.empty();
17581758

1759-
$http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}).
1760-
success(function(content) {
1759+
$$templateRequest($sce.getTrustedResourceUrl(templateUrl))
1760+
.then(function(content) {
17611761
var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
17621762

17631763
content = denormalizeTemplate(content);
@@ -1832,9 +1832,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
18321832
childBoundTranscludeFn);
18331833
}
18341834
linkQueue = null;
1835-
}).
1836-
error(function(response, code, headers, config) {
1837-
throw $compileMinErr('tpload', 'Failed to load template: {0}', config.url);
18381835
});
18391836

18401837
return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {

‎src/ng/templateRequest.js

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
'use strict';
2+
3+
var $compileMinErr = minErr('$compile');
4+
5+
function $$TemplateRequestProvider() {
6+
this.$get = ['$templateCache', '$http', function($templateCache, $http) {
7+
function handleRequestFn(tpl) {
8+
var self = handleRequestFn;
9+
self.totalPendingRequests++;
10+
11+
return $http.get(tpl, { cache : $templateCache })
12+
.then(function(response) {
13+
var html = response.data;
14+
if(!html || html.length === 0) {
15+
handleError();
16+
return;
17+
}
18+
19+
self.totalPendingRequests--;
20+
$templateCache.put(tpl, html);
21+
return html;
22+
}, handleError);
23+
24+
function handleError() {
25+
self.totalPendingRequests--;
26+
throw $compileMinErr('tpload', 'Failed to load template: {0}', tpl);
27+
}
28+
}
29+
30+
handleRequestFn.totalPendingRequests = 0;
31+
32+
return handleRequestFn;
33+
}];
34+
}

‎src/ngMessages/messages.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,8 @@ angular.module('ngMessages', [])
228228
* </file>
229229
* </example>
230230
*/
231-
.directive('ngMessages', ['$compile', '$animate', '$http', '$templateCache',
232-
function($compile, $animate, $http, $templateCache) {
231+
.directive('ngMessages', ['$compile', '$animate', '$$templateRequest',
232+
function($compile, $animate, $$templateRequest) {
233233
var ACTIVE_CLASS = 'ng-active';
234234
var INACTIVE_CLASS = 'ng-inactive';
235235

@@ -296,8 +296,8 @@ angular.module('ngMessages', [])
296296

297297
var tpl = $attrs.ngMessagesInclude || $attrs.include;
298298
if(tpl) {
299-
$http.get(tpl, { cache: $templateCache })
300-
.success(function processTemplate(html) {
299+
$$templateRequest(tpl)
300+
.then(function processTemplate(html) {
301301
var after, container = angular.element('<div/>').html(html);
302302
angular.forEach(container.children(), function(elm) {
303303
elm = angular.element(elm);

‎src/ngRoute/route.js

+3-5
Original file line numberDiff line numberDiff line change
@@ -225,10 +225,9 @@ function $RouteProvider(){
225225
'$routeParams',
226226
'$q',
227227
'$injector',
228-
'$http',
229-
'$templateCache',
228+
'$$templateRequest',
230229
'$sce',
231-
function($rootScope, $location, $routeParams, $q, $injector, $http, $templateCache, $sce) {
230+
function($rootScope, $location, $routeParams, $q, $injector, $$templateRequest, $sce) {
232231

233232
/**
234233
* @ngdoc service
@@ -525,8 +524,7 @@ function $RouteProvider(){
525524
templateUrl = $sce.getTrustedResourceUrl(templateUrl);
526525
if (angular.isDefined(templateUrl)) {
527526
next.loadedTemplateUrl = templateUrl;
528-
template = $http.get(templateUrl, {cache: $templateCache}).
529-
then(function(response) { return response.data; });
527+
template = $$templateRequest(templateUrl);
530528
}
531529
}
532530
if (angular.isDefined(template)) {

‎test/ng/templateRequestSpec.js

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
'use strict';
2+
3+
describe('$$templateCache', function() {
4+
5+
it('should download the provided template file',
6+
inject(function($rootScope, $$templateRequest, $httpBackend) {
7+
8+
$httpBackend.expectGET('tpl.html').respond('<div>abc</div>');
9+
10+
var content;
11+
$$templateRequest('tpl.html').then(function(html) { content = html; });
12+
13+
$rootScope.$digest();
14+
$httpBackend.flush();
15+
16+
expect(content).toBe('<div>abc</div>');
17+
}));
18+
19+
it('should cache the request using $templateCache to prevent extra downloads',
20+
inject(function($rootScope, $$templateRequest, $templateCache) {
21+
22+
$templateCache.put('tpl.html', 'matias');
23+
24+
var content;
25+
$$templateRequest('tpl.html').then(function(html) { content = html; });
26+
27+
$rootScope.$digest();
28+
expect(content).toBe('matias');
29+
}));
30+
31+
it('should throw an error when the template is not found',
32+
inject(function($rootScope, $$templateRequest, $httpBackend) {
33+
34+
$httpBackend.expectGET('tpl.html').respond(404);
35+
36+
$$templateRequest('tpl.html');
37+
38+
$rootScope.$digest();
39+
40+
expect(function() {
41+
$rootScope.$digest();
42+
$httpBackend.flush();
43+
}).toThrowMinErr('$compile', 'tpload', 'Failed to load template: tpl.html');
44+
}));
45+
46+
it('should throw an error when the template is empty',
47+
inject(function($rootScope, $$templateRequest, $httpBackend) {
48+
49+
$httpBackend.expectGET('tpl.html').respond('');
50+
51+
$$templateRequest('tpl.html');
52+
53+
$rootScope.$digest();
54+
55+
expect(function() {
56+
$rootScope.$digest();
57+
$httpBackend.flush();
58+
}).toThrowMinErr('$compile', 'tpload', 'Failed to load template: tpl.html');
59+
}));
60+
61+
it('should keep track of how many requests are going on',
62+
inject(function($rootScope, $$templateRequest, $httpBackend) {
63+
64+
$httpBackend.expectGET('a.html').respond('a');
65+
$httpBackend.expectGET('b.html').respond('c');
66+
$$templateRequest('a.html');
67+
$$templateRequest('b.html');
68+
69+
expect($$templateRequest.totalPendingRequests).toBe(2);
70+
71+
$rootScope.$digest();
72+
$httpBackend.flush();
73+
74+
expect($$templateRequest.totalPendingRequests).toBe(0);
75+
76+
$httpBackend.expectGET('c.html').respond(404);
77+
$$templateRequest('c.html');
78+
79+
expect($$templateRequest.totalPendingRequests).toBe(1);
80+
$rootScope.$digest();
81+
82+
try {
83+
$httpBackend.flush();
84+
} catch(e) {}
85+
86+
expect($$templateRequest.totalPendingRequests).toBe(0);
87+
}));
88+
89+
});

‎test/ngRoute/directive/ngViewSpec.js

+7-5
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ describe('ngView', function() {
5656
});
5757

5858

59-
it('should instantiate controller for empty template', function() {
59+
it('should not instantiate the associated controller when an empty template is downloaded', function() {
6060
var log = [], controllerScope,
6161
Ctrl = function($scope) {
6262
controllerScope = $scope;
@@ -70,11 +70,13 @@ describe('ngView', function() {
7070
inject(function($route, $rootScope, $templateCache, $location) {
7171
$templateCache.put('/tpl.html', [200, '', {}]);
7272
$location.path('/some');
73-
$rootScope.$digest();
7473

75-
expect(controllerScope.$parent).toBe($rootScope);
76-
expect(controllerScope).toBe($route.current.scope);
77-
expect(log).toEqual(['ctrl-init']);
74+
expect(function() {
75+
$rootScope.$digest();
76+
$httpBackend.flush();
77+
}).toThrowMinErr('$compile', 'tpload', 'Failed to load template: /tpl.html');
78+
79+
expect(controllerScope).toBeUndefined();
7880
});
7981
});
8082

‎test/ngRoute/routeSpec.js

+19-15
Original file line numberDiff line numberDiff line change
@@ -671,35 +671,39 @@ describe('$route', function() {
671671
});
672672

673673

674-
it('should drop in progress route change when new route change occurs and old fails', function() {
674+
it('should throw an error when a template is empty or not found', function() {
675675
module(function($routeProvider) {
676676
$routeProvider.
677677
when('/r1', { templateUrl: 'r1.html' }).
678-
when('/r2', { templateUrl: 'r2.html' });
678+
when('/r2', { templateUrl: 'r2.html' }).
679+
when('/r3', { templateUrl: 'r3.html' });
679680
});
680681

681682
inject(function($route, $httpBackend, $location, $rootScope) {
682-
var log = '';
683-
$rootScope.$on('$routeChangeError', function(e, next, last, error) {
684-
log += '$failed(' + next.templateUrl + ', ' + error.status + ');';
685-
});
686-
$rootScope.$on('$routeChangeStart', function(e, next) { log += '$before(' + next.templateUrl + ');'; });
687-
$rootScope.$on('$routeChangeSuccess', function(e, next) { log += '$after(' + next.templateUrl + ');'; });
688-
689683
$httpBackend.expectGET('r1.html').respond(404, 'R1');
690-
$httpBackend.expectGET('r2.html').respond('R2');
684+
$httpBackend.expectGET('r2.html').respond('');
685+
$httpBackend.expectGET('r3.html').respond('abc');
691686

692687
$location.path('/r1');
693688
$rootScope.$digest();
694-
expect(log).toBe('$before(r1.html);');
689+
690+
expect(function() {
691+
$httpBackend.flush();
692+
}).toThrowMinErr('$compile', 'tpload', 'Failed to load template: r1.html');
695693

696694
$location.path('/r2');
697695
$rootScope.$digest();
698-
expect(log).toBe('$before(r1.html);$before(r2.html);');
699696

700-
$httpBackend.flush();
701-
expect(log).toBe('$before(r1.html);$before(r2.html);$after(r2.html);');
702-
expect(log).not.toContain('$after(r1.html);');
697+
expect(function() {
698+
$httpBackend.flush();
699+
}).toThrowMinErr('$compile', 'tpload', 'Failed to load template: r2.html');
700+
701+
$location.path('/r3');
702+
$rootScope.$digest();
703+
704+
expect(function() {
705+
$httpBackend.flush();
706+
}).not.toThrowMinErr('$compile', 'tpload', 'Failed to load template: r3.html');
703707
});
704708
});
705709

0 commit comments

Comments
 (0)
Please sign in to comment.