-
Notifications
You must be signed in to change notification settings - Fork 13.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(templateCache): automatically cache template files to prevent fl…
…icker on page navigation and improve performance State templates are cached automatically, but you can optionally cache other templates. ```js $ionicTemplateCahce('myNgIncludeTemplate.html'); ``` Optionally disable all preemptive caching with the `$ionicConfigProvider` or individual states by setting `prefetchTemplate` in the $state definition ```js $ionicTemplateCahce('myNgIncludeTemplate.html'); ```js angular.module('myApp', ['ionic']) .config(function($stateProvider, $ionicConfigProvider) { // disable preemptive template caching globally $ionicConfigProvider.prefetchTemplates(false); // disable individual states $stateProvider .state('tabs', { url: "/tab", abstract: true, prefetchTemplate: false, templateUrl: "tabs-templates/tabs.html" }) .state('tabs.home', { url: "/home", views: { 'home-tab': { prefetchTemplate: false, templateUrl: "tabs-templates/home.html", controller: 'HomeTabCtrl' } } }); }); ```
- Loading branch information
1 parent
834e2bb
commit 944a92b
Showing
9 changed files
with
359 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
// closure to keep things neat | ||
(function() { | ||
var templatesToCache = []; | ||
|
||
/** | ||
* @ngdoc service | ||
* @name $ionicTemplateCache | ||
* @module ionic | ||
* @description An angular service that preemptively caches template files to reduce flicker and boost performance. | ||
* @usage | ||
* State templates are cached automatically, but you can optionally cache other templates. | ||
* ```js | ||
* $ionicTemplateCahce('myNgIncludeTemplate.html'); | ||
* ``` | ||
* | ||
* Optionally disable all preemptive caching with the `$ionicConfigProvider` or individual states by setting `prefetchTemplate` | ||
* in the $state definition | ||
* ```js | ||
* $ionicTemplateCahce('myNgIncludeTemplate.html'); | ||
* ```js | ||
* angular.module('myApp', ['ionic']) | ||
* .config(function($stateProvider, $ionicConfigProvider) { | ||
* | ||
* // disable preemptive template caching globally | ||
* $ionicConfigProvider.prefetchTemplates(false); | ||
* | ||
* // disable individual states | ||
* $stateProvider | ||
* .state('tabs', { | ||
* url: "/tab", | ||
* abstract: true, | ||
* prefetchTemplate: false, | ||
* templateUrl: "tabs-templates/tabs.html" | ||
* }) | ||
* .state('tabs.home', { | ||
* url: "/home", | ||
* views: { | ||
* 'home-tab': { | ||
* prefetchTemplate: false, | ||
* templateUrl: "tabs-templates/home.html", | ||
* controller: 'HomeTabCtrl' | ||
* } | ||
* } | ||
* }); | ||
* }); | ||
* ``` | ||
*/ | ||
IonicModule | ||
.factory('$ionicTemplateCache', [ | ||
'$http', | ||
'$templateCache', | ||
'$timeout', | ||
'$ionicConfig', | ||
function($http, $templateCache, $timeout, $ionicConfig) { | ||
var toCache = templatesToCache, | ||
hasRun = false; | ||
/** | ||
* @ngdoc method | ||
* @name $ionicTemplateCache | ||
* @description Add template(s) to be cached. | ||
* @param {string | array} string or array of strings of templates to cache. | ||
*/ | ||
function $ionicTemplateCache(templates){ | ||
if(toCache.length > 500) return false; | ||
if(typeof templates === 'undefined')return run(); | ||
if(isString(templates))templates = [templates]; | ||
forEach(templates, function(template){ | ||
toCache.push(template); | ||
}); | ||
// is this is being called after the initial IonicModule.run() | ||
if(hasRun) run(); | ||
} | ||
|
||
// run through methods - internal method | ||
var run = function(){ | ||
if($ionicConfig.prefetchTemplates === false)return | ||
//console.log('prefetching', toCache); | ||
//for testing | ||
$ionicTemplateCache._runCount++; | ||
|
||
hasRun = true; | ||
// ignore if race condition already zeroed out array | ||
if(toCache.length === 0)return; | ||
//console.log(toCache); | ||
var i = 0; | ||
while ( i < 5 && (template = toCache.pop()) ) { | ||
// note that inline templates are ignored by this request | ||
if (isString(template)) $http.get(template, { cache: $templateCache }); | ||
i++; | ||
} | ||
// only preload 5 templates a second | ||
if(toCache.length)$timeout(function(){run()}, 1000); | ||
}; | ||
|
||
// exposing for testing | ||
$ionicTemplateCache._runCount = 0; | ||
// default method | ||
return $ionicTemplateCache; | ||
}]) | ||
|
||
/** | ||
* @ngdoc config | ||
* @name $ionicTemplateCache | ||
* @module ionic | ||
* @private | ||
* | ||
* Intercepts the $stateprovider.state() command to look for templateUrls that can be cached | ||
*/ | ||
.config([ | ||
'$stateProvider', | ||
'$ionicConfigProvider', | ||
function($stateProvider, $ionicConfigProvider) { | ||
var stateProviderState = $stateProvider.state; | ||
$stateProvider.state = function(stateName, definition) { | ||
// don't even bother if it's disabled. note, another config may run after this, so it's not a catch-all | ||
if($ionicConfigProvider.prefetchTemplates() !== false){ | ||
var enabled = definition.prefetchTemplate != false; | ||
if(enabled && isString(definition.templateUrl))templatesToCache.push(definition.templateUrl); | ||
if(angular.isObject(definition.views)){ | ||
for (var key in definition.views){ | ||
enabled = definition.views[key].prefetchTemplate != false; | ||
if(enabled && isString(definition.views[key].templateUrl)) templatesToCache.push(definition.views[key].templateUrl); | ||
} | ||
} | ||
} | ||
return stateProviderState.call($stateProvider, stateName, definition); | ||
}; | ||
}]) | ||
|
||
/** | ||
* @ngdoc run | ||
* @name $ionicTemplateCache | ||
* @module ionic | ||
* @private | ||
* | ||
* process the templateUrls collected by the $stateProvider, adding them to the cache | ||
*/ | ||
.run(function($ionicTemplateCache) { | ||
$ionicTemplateCache(); | ||
}); | ||
|
||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
<html ng-app="ionicApp"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width"> | ||
|
||
<title>Tabs Example</title> | ||
|
||
<link href="../../../../dist/css/ionic.css" rel="stylesheet"> | ||
|
||
</head> | ||
|
||
<body> | ||
|
||
<ion-nav-bar class="nav-title-slide-ios7 bar-positive"> | ||
<ion-nav-back-button class="button-icon ion-arrow-left-c"> | ||
</ion-nav-back-button> | ||
</ion-nav-bar> | ||
|
||
<ion-nav-view animation="slide-left-right"></ion-nav-view> | ||
|
||
<script id="tabs-templates/contact.html" type="text/ng-template"> | ||
<ion-view title="Contact"> | ||
<ion-content> | ||
<div class="list"> | ||
<div class="item"> | ||
@IonicFramework | ||
</div> | ||
<div class="item"> | ||
@DriftyTeam | ||
</div> | ||
</div> | ||
</ion-content> | ||
</ion-view> | ||
</script> | ||
|
||
|
||
<script src="../../../../dist/js/ionic.bundle.js"></script> | ||
<script> | ||
angular.module('ionicApp', ['ionic']) | ||
|
||
.config(function($stateProvider, $ionicConfigProvider) { | ||
|
||
$ionicConfigProvider.prefetchTemplates(false); | ||
|
||
$stateProvider | ||
.state('tabs', { | ||
url: "/tab", | ||
abstract: true, | ||
templateUrl: "tabs-templates/tabs.html" | ||
}) | ||
.state('tabs.home', { | ||
url: "/home", | ||
views: { | ||
'home-tab': { | ||
templateUrl: "tabs-templates/home.html", | ||
controller: 'HomeTabCtrl' | ||
} | ||
} | ||
}) | ||
.state('tabs.facts', { | ||
url: "/facts", | ||
views: { | ||
'home-tab': { | ||
templateUrl: "tabs-templates/facts.html" | ||
} | ||
} | ||
}) | ||
.state('tabs.facts2', { | ||
url: "/facts2", | ||
views: { | ||
'home-tab': { | ||
templateUrl: "tabs-templates/facts2.html" | ||
} | ||
} | ||
}) | ||
.state('tabs.about', { | ||
url: "/about", | ||
views: { | ||
'about-tab': { | ||
templateUrl: "tabs-templates/about.html" | ||
} | ||
} | ||
}) | ||
.state('tabs.navstack', { | ||
url: "/navstack", | ||
views: { | ||
'about-tab': { | ||
templateUrl: "tabs-templates/nav-stack.html", | ||
prefetchTemplate:false | ||
} | ||
} | ||
}) | ||
.state('tabs.contact', { | ||
url: "/contact", | ||
views: { | ||
'contact-tab': { | ||
templateUrl: "tabs-templates/contact.html" | ||
} | ||
} | ||
}); | ||
|
||
|
||
$urlRouterProvider.otherwise("/tab/home"); | ||
|
||
}) | ||
|
||
.controller('HomeTabCtrl', function($scope, $ionicTemplateCache) { | ||
$ionicTemplateCache('test'); | ||
}); | ||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<ion-view title="About"> | ||
<ion-content class="padding"> | ||
<h3>Create hybrid mobile apps with the web technologies you love.</h3> | ||
<p>Free and open source, Ionic offers a library of mobile-optimized HTML, CSS and JS components for building highly interactive apps.</p> | ||
<p>Built with Sass and optimized for AngularJS.</p> | ||
<p> | ||
<a class="button icon icon-right ion-chevron-right" href="#/tab/navstack">Tabs Nav Stack</a> | ||
</p> | ||
</ion-content> | ||
</ion-view> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<ion-view title="Facts"> | ||
<ion-content class="padding"> | ||
<p>Banging your head against a wall uses 150 calories an hour.</p> | ||
<p>Dogs have four toes on their hind feet, and five on their front feet.</p> | ||
<p>The ant can lift 50 times its own weight, can pull 30 times its own weight and always falls over on its right side when intoxicated.</p> | ||
<p>A cockroach will live nine days without it's head, before it starves to death.</p> | ||
<p>Polar bears are left handed.</p> | ||
<p> | ||
<a class="button icon ion-home" href="#/tab/home"> Home</a> | ||
<a class="button icon icon-right ion-chevron-right" href="#/tab/facts2">More Facts</a> | ||
</p> | ||
</ion-content> | ||
</ion-view> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<ion-view title="Also Factual"> | ||
<ion-content class="padding"> | ||
<p>111,111,111 x 111,111,111 = 12,345,678,987,654,321</p> | ||
<p>1 in every 4 Americans has appeared on T.V.</p> | ||
<p>11% of the world is left-handed.</p> | ||
<p>1 in 8 Americans has worked at a McDonalds restaurant.</p> | ||
<p>$283,200 is the absolute highest amount of money you can win on Jeopardy.</p> | ||
<p>101 Dalmatians, Peter Pan, Lady and the Tramp, and Mulan are the only Disney cartoons where both parents are present and don't die throughout the movie.</p> | ||
<p> | ||
<a class="button icon ion-home" href="#/tab/home"> Home</a> | ||
<a class="button icon ion-chevron-left" href="#/tab/facts"> Scientific Facts</a> | ||
</p> | ||
</ion-content> | ||
</ion-view> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<ion-view title="Home"> | ||
<ion-content class="padding"> | ||
<p>Example of Ionic tabs. Navigate to each tab, and | ||
navigate to child views of each tab and notice how | ||
each tab has its own navigation history.</p> | ||
<p> | ||
<a class="button icon icon-right ion-chevron-right" href="#/tab/facts">Scientific Facts</a> | ||
</p> | ||
</ion-content> | ||
</ion-view> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<ion-view title="Tab Nav Stack"> | ||
<ion-content class="padding"> | ||
<p><img src="http://ionicframework.com/img/diagrams/tabs-nav-stack.png" style="width:100%"></p> | ||
</ion-content> | ||
</ion-view> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<ion-tabs class="tabs-icon-top tabs-positive"> | ||
|
||
<ion-tab title="Home" icon="ion-home" href="#/tab/home"> | ||
<ion-nav-view name="home-tab"></ion-nav-view> | ||
</ion-tab> | ||
|
||
<ion-tab title="About" icon="ion-ios7-information" href="#/tab/about"> | ||
<ion-nav-view name="about-tab"></ion-nav-view> | ||
</ion-tab> | ||
|
||
<ion-tab title="Contact" icon="ion-ios7-world" ui-sref="tabs.contact"> | ||
<ion-nav-view name="contact-tab"></ion-nav-view> | ||
</ion-tab> | ||
|
||
</ion-tabs> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
describe('$ionicTemplateCache', function() { | ||
beforeEach(module('ionic')); | ||
|
||
beforeEach(inject(function($ionicTemplateCache, $templateCache) { | ||
ionicTemplateCache = $ionicTemplateCache; | ||
templateCache = $templateCache; | ||
})); | ||
|
||
it('should run during initial startup', function () { | ||
var info = templateCache.info(); | ||
expect(info.size).toBe(0); | ||
expect(ionicTemplateCache._runCount).toBe(1); | ||
}); | ||
|
||
it('should run immediately after a new addition after initial run', inject(function ($templateCache, $httpBackend, $timeout) { | ||
$httpBackend.whenGET("/test").respond([{hello:"world"}]); | ||
ionicTemplateCache('/test'); | ||
$timeout.flush(); | ||
var info = templateCache.info(); | ||
expect(info.size).toBe(1); | ||
expect(ionicTemplateCache._runCount).toBe(2); | ||
})); | ||
|
||
it('should cache 5 templates at a time', inject(function ($httpBackend, $timeout) { | ||
$httpBackend.whenGET("/test1").respond([{hello:"world"}]); | ||
$httpBackend.whenGET("/test2").respond([{hello:"world"}]); | ||
$httpBackend.whenGET("/test3").respond([{hello:"world"}]); | ||
$httpBackend.whenGET("/test4").respond([{hello:"world"}]); | ||
$httpBackend.whenGET("/test5").respond([{hello:"world"}]); | ||
$httpBackend.whenGET("/test6").respond([{hello:"world"}]); | ||
$httpBackend.whenGET("/test7").respond([{hello:"world"}]); | ||
ionicTemplateCache(['/test1','/test2','/test2','/test3','/test4','/test5','/test6','/test7']); | ||
$timeout.flush(); | ||
var info = templateCache.info(); | ||
expect(info.size).toBe(7); | ||
expect(ionicTemplateCache._runCount).toBe(3); | ||
})); | ||
}); |