原文:http://davidcai.github.io/blog/posts/router-dynamic-templates/

ui-router : templateProvider vs template

----------------------------------------------

Router: Dynamic Templates

Sat Aug 15, 2015

Dynamic templates

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.

  • Categories: 
  • angular
  • test

angular—— Dynamic Templates相关推荐

  1. 【Elasticsearch】Elasticsearch 动态模板(Dynamic templates)

    1.概述 动态映射请参考: [Elasticsearch]Elasticsearch 7 : 动态映射 dynamic 本博客摘抄自:Elastic Stack 实战手册(早鸟版).pdf 原文可看, ...

  2. Elasticsearch:Dynamic templates

    这篇文章和之前的 "Elasticsearch:Dynamic mapping" 有重复的地方.那篇文章是在很久以前创作的.由于有了 runtime fields 的新功能,我在这 ...

  3. angular dynamic component 笔记

    使用到动态组件是因为我在做一个Table的控件,表格中有按钮等控件,并具有相应逻辑,同时项目中多处使用到该表格,故想提取一个可复用的控件以减少工作量.主要参考的文章是大神的修仙之路Angular 4. ...

  4. 三:Angular 模板 (Templates)

    1 什么是模板 它是页面呈现的骨架,是盛装组件数据的容器.与之相关的内容包括了-----模板与组件件 '数据交互'.'内置指令'.'表单'.'管道'等. 1.1 模板语法概览 //插值:绑定属性变量的 ...

  5. angular react_Angular 2 vs React:将会有鲜血

    angular react Angular 2 has reached Beta and appears poised to become the hot new framework of 2016. ...

  6. Angular动态创建组件

    Angular动态创建组件 什么是动态创建? 一般来说就是组件不需要在html内定义,而是通过typescript来控制该组件的创建.往往我们大部分的时候都是在html内定义,之所以这样也能够创建出我 ...

  7. Elasticsearch之Mapping

    Mapping 类似数据库中的表机构定义,主要作用如下: - 定义Index下的字段名(FieldName) - 定义字段的类型,比如数值型.字符串型.布尔型等 - 定义倒排索引相关的配置,比如是否索 ...

  8. elasticsearch索引和映射

    目录 1. elasticsearch如何实现搜索 1.1 搜索实例 1.2 es中数据的类型 1.3 倒排索引 1.4 分析与分析器 1.4.1 什么是分析器 1.4.2 内置分析器种类 1.4.3 ...

  9. 04.elasticsearch-dynamic_mapping_and_index_template

    文章目录 1. dynamic mapping 设置 1. es内部支持的field类型的动态识别 1. 默认的field 识别 2. date-detection 3. numeric-detect ...

最新文章

  1. 订体育馆订健身房的方法
  2. mysql like 中文版_MySQL使用like查询中文不准确的解决方法
  3. 函数在内存中的具体执行
  4. 【Spring学习】IOC容器
  5. UCGUI的模拟器UCGUISim详解
  6. 在HTML网页中使用ActiveX控件
  7. 【BZOJ2243】 [SDOI2011]染色
  8. 抢占式和非抢占式的进程调度
  9. 禁止html文件控件手动输入的方法
  10. 双向关联一对一映射详解(1)
  11. 洛阳计算机学校排名2015年,洛阳最好的中专学校有哪些 十大中专学校排名
  12. swing获取文本框内容_Swing 使用 JTable详解
  13. selenium 学习之路开始了,一遍搬一遍理解学习,加油!!!
  14. 白事碰上红事,徐渭应景吟诗
  15. 报错Could not find module ‘D:\Anaconda\lib\site-packages\scipy\.libs\
  16. 博士申请 | 伦敦玛丽女王大学Yuanwei Liu老师组招收通信计算机博士生
  17. 初学QT 实现简单游戏打地鼠
  18. pycharm2017.3.3破解到2099年
  19. react-navigation 6.x 学习(3)
  20. SqlSugar 1.项目安装

热门文章

  1. Visual Studio 2008 SDK Version 和Microsoft Visual Studio 2008 Shell发布了
  2. 手机APP应用如何从公网访问本地WEB应用
  3. java,andoid安卓去掉替换字符串中的空字符空格换行等
  4. MATLAB脚本显示滤波器系数
  5. 三言两语话敏捷(2) - 持续集成
  6. Microsoft Active Directory(LDAP)连接常见错误代码
  7. QEMU, KVM, QEMU-KVM 和 Goldfish
  8. Java中SimpleDateFormat用法详解
  9. Android 百度地图开发(三)--- 实现比例尺功能和替换自带的缩放组件
  10. 2018年终盘点:“年度爆款”的区块链真的结束了吗?