angular—— Dynamic Templates
原文:http://davidcai.github.io/blog/posts/router-dynamic-templates/
ui-router : templateProvider vs template
----------------------------------------------
Router: Dynamic Templates
Sat Aug 15, 2015

This post discusses how to create dynamic templates by leveraging the templateProvider configuration provided by Angular’s built-in router or the third-party UI Router.
PROBLEM
For Single Page Applications (SPAs), we often need to switch views or states inside containers. This is usually done through routers. With either Angular’s built-in router or the popular UI Router, we are able to define the relationship between states and their templates. For instance, here we defined a state home and its template URL app/home/home.html:
app.config(function($stateProvider) {
$stateProvider.state('home', {
url: '/',
templateUrl: 'app/home/home.html'
});
});
In some cases, this state-to-template relationship can not be determined beforehand at the config time. The decision of what the template or template URL will be used for a state has to wait for the availability of run-time data. For example:
- User’s account type, e.g. show Home version A for members, and version B for public users.
- A/B testing, e.g. a A/B testing service randomly picks from two versions – A or B.
In either scenario, the template cannot be fixed to app/home/home.html, and has be to resolved using run-time data.
Router’s templateUrl configuration accepts a function which can be used to create dynamic template URL. However, we are not able to inject run-time dependencies (e.g. user services, or A/B test services) into the templateUrl function. The only available argument of the templateUrl function is $stateParams.
$stateProvider.state('home', {
templateUrl: function($stateParams) { // Can not inject dependencies
return 'app/home.' + $stateParams.option + '.html';
}
});
SOLUTION
The answer is templateProvider.
Both Angular built-in router and the UI Router have a templateProvider configuration. templateProvider accepts a function that can be injected with run-time dependencies.
$stateProvider.state('home', {
templateProvider: function(abTestService) { // abTestService is injected here
var result = abTestService.pick('a', 'b'); // Choose version A or B
return '...'; // Return template content based on the result
}
});
templateProvider returns template content (not an URL to the template). We can certainly embed HTML markups directly in JavaScript, but for complicate HTML, it’s better to externalize the HTML content to separate template files. Here, we created home-a.html and home-b.html, and ngInclude them in the templateProvider function:
<!-- Home version A at app/home/home-a.html -->
<div ng-controller="HomeAController">Version A</div>
<!-- Home version B at app/home/home-b.html -->
<div ng-controller="HomeBController">Version B</div>
$stateProvider.state('home', {
templateProvider: function(abTestService) {
var result = abTestService.pick('a', 'b');
// ngInclude template content based on the A/B test result
return '<div ng-include="\'app/home/home-' + result + '.html\'"></div>';
}
});
templateProvider can also return a Promise which is resolved to template content.
$stateProvider.state('home', {
templateProvider: function($http, USER_SERVICE_REST_URL) {
// Here, we return a promise instead of the template content
return $http.get(USER_SERVICE_REST_URL).then(function(data) {
var result = (data.type === 'member' ? 'a' : 'b');
// Return the template content
return '<div ng-include="\'app/home/home-' + result + '.html\'"></div>';
});
}
});
EVEN BETTER SOLUTION
Having ngInclude in templateProvider function feels still a bit hackish to me. The ideal solution is to specify a template URL, and then let Angular fetch the content. However, sending separate HTTP requests just to fetch templates seems to be unnecessary web traffic. It will be better if the template content can be cached in the $templateCache service; and then, all I need to do is $templateCache.get('templateUrl'):
$stateProvider.state('home', {
templateProvider: function(abTestService, $templateCache) {
var result = abTestService.pick('a', 'b');
// Retrieve the cached template content from $templateCache service
return $templateCache.get('app/home/home-' + result + '.html');
}
});
To achieve this, we need a Gulp task to convert all HTML files under the app/ directory to JavaScript strings, and save the strings in $templateCache.
// Load gulp and its plugins
var gulp = require('gulp');
var minifyHtml = require('gulp-minify-html');
var angularTemplateCache = require('gulp-angular-templatecache');
gulp.task('templates', function() {
return cacheTemplates('src/app/**/*.html', 'app.template.js');
function cacheTemplates(input, output) {
return gulp.src(input) // Get all HTML files
.pipe(minifyHtml({ // Minify HTML content first
empty: true,
spare: true,
quotes: true
}))
.pipe(angularTemplateCache(output, { // Save minified strings to cache
module: 'myApp' // Setup $templateCache for Angular module 'myApp'
}))
.pipe(gulp.dest('.tmp/templates/'));
} // /function cacheTemplates
});
Then, import the generated template.js in index.html:
<script src=".tmp/templates/app.template.js"></script>
CONCLUSION
By leveraging the templateProvider function that can be injected with dependencies, we are able to resolve template content based on run-time data. This technique is useful for switching among more than one templates for a state, for instance, A/B testing, and swappable content in limited space.
angular—— Dynamic Templates的更多相关文章
- ES - Dynamic templates 动态模板
1.ES Mapping 在lucene中,索引中每个字段都需要指定很多属性,例如:是否分词.采用哪个分词器.是否存储等. 在ES中,其实索引中每个字段也需要指定这些属性,我们有时候并没有对这些属性进 ...
- [Angular 2] Set Values on Generated Angular 2 Templates with Template Context
Angular 2 templates have a special let syntax that allows you to define and pass a context when they ...
- [Angular] Dynamic component's instance and sorting
After create a component dynamic, we are able to change the component's props and listen to its even ...
- [Angular] Dynamic component rendering by using *ngComponentOutlet
Let's say you want to rending some component based on condition, for example a Tabs component. Insid ...
- [Angular] Dynamic components with ComponentFactoryResolver
To create a component dynamicly. 1. Add a container with ref: @Component({ selector: 'app-root', tem ...
- ANGULAR 2 FOR REACT DEVELOPERS
Now that Angular 2 is in beta, the time has come for us to drop everything and learn something new, ...
- [Angular 2] Create template with Params
Angular 2 templates have a special let syntax that allows you to define and pass a context when they ...
- [Angular 2] Generate and Render Angular 2 Template Elements in a Component
Angular 2 Components have templates, but you can also create templates inside of your templates usin ...
- [Angular 2] Rendering an Observable with the Async Pipe
Angular 2 templates use a special Async pipe to be able to render out Observables. This lesson cover ...
随机推荐
- Oracle基础 11 约束 constraints
--主.外键约束 create table t( id int primary key); create table t1( id int references t(id)); 或者create ...
- k8s通过label来控制pod的位置
默认情况下,scheduler会将pod调度到所有可用的Node,不过有些情况我们希望将 Pod 部署到指定的 Node,比如将有大量磁盘 I/O 的 Pod 部署到配置了 SSD 的 Node:或者 ...
- mysql之any,some all(zz)
转载自:http://blog.csdn.net/netcy/article/details/8464503 ALL和ANY操作符的常见用法是结合一个相对比较操作符对一个数据列子查询的结果进行测试.它 ...
- Ubuntu-16.04安装Xdebug-2.2.5及相关介绍
Xdebug是一个开放源代码的PHP程序调试器(即一个Debug工具),可以用来跟踪,调试和分析PHP程序的运行状况.在日常开发中,我们会使用如 print_r() var_dump()等函数来进行调 ...
- 如何正确学习web前端流程以及如何找工作
解释一下web前端工作是做啥的,Web前端开发工程师,主要职责是利用(X)HTML/CSS/JavaScript/Flash等各种Web技术进行客户端产品的开发.完成客户端程序(也就是浏览器端)的开发 ...
- (一)mysql基础和安装mysql5.7
(1)数据库系统 RDS:关系型,oracle,mysql,mariaDB,percona server ,DB2 NoSQL:Redis,MongoDB,memcache (2)SQL语言:结构化查 ...
- (20)python pycharm
使用GitHub 一·登录GitHub 1. 2. 3. 4. 二. 登录成功后再配置git 1 2.创建项目到github 3.下载github
- (3)python 列表和元组
列表 元组 字段 等都是一种数据结构.其中列表和元组比较相似都是顺序保存的,都可以通过索引来找到元素. 列表和元组的主要区别:列表是可以修改的,元组不可以修改.列表用[]表示,元组用()表示 一.列表 ...
- Educational Codeforces Round 30 B【前缀和+思维/经典原题】
B. Balanced Substring time limit per test 1 second memory limit per test 256 megabytes input standar ...
- floyed算法的一些感想
for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=k;j++) if(f[i][k]+f[k][j]<f[i ...