原文: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的更多相关文章

  1. ES - Dynamic templates 动态模板

    1.ES Mapping 在lucene中,索引中每个字段都需要指定很多属性,例如:是否分词.采用哪个分词器.是否存储等. 在ES中,其实索引中每个字段也需要指定这些属性,我们有时候并没有对这些属性进 ...

  2. [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 ...

  3. [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 ...

  4. [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 ...

  5. [Angular] Dynamic components with ComponentFactoryResolver

    To create a component dynamicly. 1. Add a container with ref: @Component({ selector: 'app-root', tem ...

  6. 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, ...

  7. [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 ...

  8. [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 ...

  9. [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 ...

随机推荐

  1. Page.Response.Buffer与Response.Redirect一起用报错“无法在发送 HTTP 标头之后进行重定向”

    Page.Response.Buffer与Response.Redirect一起用报错“无法在发送 HTTP 标头之后进行重定向” 原因还未知..

  2. 【SQL】视图

    一.虚拟视图 由create table定义的表:以物理形式存在,实际存储在数据库中 视图:虚拟的,并不是一个真正存在的表 1.视图定义 CREATE VIEW <视图名> AS < ...

  3. ATM+购物车系统

    ATM目录 start.py import os,sys from core import src base_path=os.path.dirname(os.path.dirname(__file__ ...

  4. win32 sdk列表视图控件(ListCtrl或ListView)资料整理

    列表视图控件是一种非常常用的控件,在需要以报表形式显示数据时,列表控件通常是最好的选择,许多专用的数据报表控件,也是在它的基础上派生而来.与树视图类似,列表控件可以由多个子项目组成,可以设置为Icon ...

  5. IOC(控制反转)的理解

    1.IOC的理论背景 我们知道在面向对象设计的软件系统中,它的底层都是由N个对象构成的,各个对象之间通过相互合作,最终实现系统地业务逻辑[1]. 图1 软件系统中耦合的对象 如果我们打开机械式手表的后 ...

  6. 华为MateBook笔记本对比微软Surface Pro 4,谁更好?

    继上网本.超极本等概念之后,变形本和二合一设备逐渐升温,今年终于整体爆发,继苹果的iPad Pro.微软的Surface Pro 4之后,华为推出了自己的第一部电脑产品同时也是二合一设备的华为Mate ...

  7. 一句话木马与caidao

    实验吧有个试验环境:http://www.shiyanbar.com/experiment-course/experiment-course/vid/1812 菜刀的主要功能是用来连接一句话木马的,a ...

  8. POJ1861 Network(Kruskal)(并查集)

    Network Time Limit: 1000MS     Memory Limit: 30000K Total Submissions: 16047   Accepted: 6362   Spec ...

  9. sed 手册 http://www.gnu.org/software/sed/manual/sed.html

    http://www.gnu.org/software/sed/manual/sed.html

  10. centos7下mail邮件的查看删除、禁止部分应用发邮件

    查看与删除 mail命令进入 & p                  #显示当前邮件& 2                  #显示标号为2的文件 & d 1-100     ...