angularjs下载中怎么操作元素属性

AngularJS Custom Directives好讨厌不带日期的博客,而且说得好啰嗦自定义指令介绍AngularJS 指令作用是在 AngulaJS 应用中操作 Html 渲染。比如说,内插指令 ({{ }}),ng-repeat指令以及ng-if指令。当然你也可以实现自己的。这就是 AngularJS 所谓的&教会 HTML 玩新姿势”。本文将告诉你如何做到。指令类型可以自定义的指令类型如下:元素属性CSS classComment directives这里面,AngularJS 强烈建议你用元素和属性类型,而不用 CSS class 和 comment directives (除非迫不得已)。指令类型决定了指令何时被激活。当 AngularJS 在 HTML 模板中找到一个 HTML 元素的时候,元素指令被激活。当 AngularJS 找到一个 HTML 元素属性时,属性指令被激活。当 AngularJS 找到一个 CSS class 时, CSS class 指令被激活,最后,当 AngularJS 找到 HTML comment 时,comment directive 被激活。基础例子你可以向模块注册一个指令,像这样:myapp = angular.module(&myapp&, []);myapp.directive('div', function() {var directive = {};directive.restrict = 'E'; /* restrict this directive to elements */directive.template = &My first directive: {{textToInsert}}&;});来看模块中调用的directive()函数。当你调用该函数时,意味着你要注册一个新指令。directive()函数的第一个参数是新注册指令的名称。这是之后你在 HTML 模板中调用它的时候用的名称。例子中,我用了'div',意思是说当 HTML 模板每次在找到 HTML 元素类型是div的时候,这个指令都会被激活。传递给directive函数的第二个参数是一个工厂函数。调用该函数会返回一个指令的定义。 AngularJS 通过调用该函数来获取包含指令定义的 Javascript 对象。如果你有仔细看上面的例子,你会知道它返回的确是是一个 Javascript 对象。这个从工厂函数中返回的 Javascript 对象有两个属性:restrict和template字段。restrict字段用来设置指令何时被激活,是匹配到 HTML 元素时,还是匹配到元素属性时。也就是指令类型。把restrict设置为E时,只有名为div的 HTML 元素才会激活该指令。把restrict设置为A时,只有名为div的 HTML 元素属性才会激活该指令。你也可以用AE,这样会使得匹配到元素名和元素属性名时,都可以激活该指令。template字段是一个 HTML 模板,用来替换匹配的div元素。它会把匹配到的div当成一个占位符,然后用 HTML 模板在同一位置来替换掉它。也就是说,HTML 模板替换匹配的到 HTML 元素。比如说你的 HTML 页面有这样一段 HTML:&div ng-controller=&MyController& &&div&This div will be replaced&/div&&/div&当 AngularJS 找到内嵌的div的时候,会激活自定义的指令。然后把该div元素替换掉,替换后的 HTML 将变成这样:My first directive: {{textToInsert}}然后你看到了,这段 HTML 里面包含了一个内插指令 ({{textToInsert}})。AngularJS 会再执行一次,让内插指令实际值显示出来。然后 $scope.textToInsert 属性将会在这个 HTML 点上替换掉内插指令占位符。template 和 templateUrl 属性创建自定义指令最简单的例子就是上面这样了。你的指令用来生成 HTML,然后你把 HTML 放到指令定义对象的template属性中。下面这个例子是上面那最简单的例子的重复,注意template部分:myapp = angular.module(&myapp&, []);myapp.directive('div', function() {var directive = {};directive.restrict = 'E'; /* restrict this directive to elements */directive.template = &My first directive: {{textToInsert}}&;});如果 HTML 模板越来越大,把它写在一个 Javascript 字符串中肯定非常难维护。你可以把它放到一个单独的文件中,然后 AngularJS 可以通过这个文件把它加载进来。然后再把 HTML 模板文件的 URL 放到指令定义对象的templateUrl属性中。下面是例子:myapp = angular.module(&myapp&, []);myapp.directive('div', function() {var directive = {};directive.restrict = 'E'; /* restrict this directive to elements */directive.templateUrl = &/myapp/html-templates/div-template.html&;});然后 AngularJS 会从templateUrl属性中设置的 URL 将 HTML 模板加载进来。用独立的 HTML 模板文件,设置templateUrl属性,在你要创建更多的通用指令时会显得更加有用,比如说用来显示用户信息的指令。例子:myapp = angular.module(&myapp&, []);myapp.directive('userinfo', function() {var directive = {};directive.restrict = 'E'; /* restrict this directive to elements */directive.templateUrl = &/myapp/html-templates/userinfo-template.html&;});例子创建了一个指令,当AngularJS 找到一个&userinfo&元素的时候就会激活它。AngularJS 加载指向/myapp/html-templates/userinfo-template.html的模板并解析它,它就像从一开始就被嵌在上一级 HTML 文件中一样。从指令中隔离 $scope在上面的例子中,把userinfo指令硬绑定到了$scope,因为 HTML 模板是直接引用textToInsert属性的。直接引用$scope让指令在同一个controller中的时候,非常难复用,因为$scope在同一个controller中的值都是一样的。比如说,你在页面的 HTML 中这样写的时候:&userinfo&&/userinfo&&userinfo&&/userinfo&这两个&userinfo&元素会被同样的 HTML 模板取代,然后绑定到同样的$scope变量上。结果就是两个&userinfo&元素将会被一模一样的 HTML 代码给替换了。为了把两个&userinfo&元素绑定到$scope中的不同的值,你需要给 HTML 模板一个isolate scope。所谓 isolate scope 是绑定在指令上的独立的 scope 对象。下面是定义的例子:myapp.directive('userinfo', function() { var directive = {}; directive.restrict = 'E'; directive.template = &User : {{user.firstName}} {{user.lastName}}&; directive.scope = {
user : &=user& } })请看 HTMl 模板中的两个内插指令{{user.firstName}}和{{user.lastName}}。注意user.部分。以及directive.scope属性。directive.scope是个带user属性的 Javascript 对象。于是directive.scope就成为了isolate scope对象,现在 HTML 模板被绑到了directive.scope.user上(通过{{user.firstName}}和{{user.lastName}}内插指令)。directive.scope.user被设置为 “=user” 。意思是说directive.scope.user和scope中的属性绑在一起的(不是 isolate scope),scope中的属性通过user属性传入&userinfo&元素。听起来挺费劲的,直接看例子:&userinfo user=&jakob&&&/userinfo&&userinfo user=&john&&&/userinfo&这两个&userinfo&元素都有user属性。user的值指向了$scope中同名属性,被指定的$scope中的属性将在userinfo的isolate scope object中被使用。下面是完整的例子:&userinfo user=&jakob&&&/userinfo&&userinfo user=&john&&&/userinfo&&script&myapp.directive('userinfo', function() { var directive = {}; directive.restrict = 'E'; directive.template = &User : &b&{{user.firstName}}&/b& &b&{{user.lastName}}&/b&&; directive.scope = {
user : &=user& } });myapp.controller(&MyController&, function($scope, $http) { $scope.jakob = {}; $scope.jakob.firstName = &Jakob&; $scope.jakob.lastName= &Jenkov&; $scope.john = {}; $scope.john.firstName = &John&; $scope.john.lastName= &Doe&;});&/script&compile() 和 link() 函数如果你需要在你的指令中做更高级的操作,单纯使用 HTML 模板做不到的时候,你可以考虑使用compile()和link()函数。compile()和link()函数定义了指令如何修改匹配到的 HTML。当指令第一次被 AngularJS 编译的时候 (在 HTML 中第一次被发现),compile()函数被调用。compile()函数将为该元素做一次性配置。然后compile()函数以返回link()作为终结。link()函数将在每次元素被绑到$scope数据时,都被调用。下面是例子:&script&myapp = angular.module(&myapp&, []);myapp.directive('userinfo', function() { var directive = {}; directive.restrict = 'E'; /* restrict this directive to elements */ pile = function(element, attributes) {
// do one-time configuration of element.
var linkFunction = function($scope, element, atttributes) {
// bind element to data in $scope
return linkF } }); &/script&`&br /&compile()函数带两个参数:element和attributes`。element参数是 jqLite 包装过的 DOM 元素。AngularJS 有一个简化版 jQuery 可以用于操作 DOM,所以对element的 DOM 操作方式和你在 jQuery 中所知的一样。attributes参数是包含了 DOM 元素中的所有的属性集合的 Javascript 对象。因此,你要访问某个属性你可以这样写attributes.type。link()函数带三个参数:$scope,element和attributes。element和attributes参数和传到compile()函数中的一样。$scope参数是正常的 scope 对象,或者当你在指令定义对象中定义了 isolate scope 的时候,它就是 isolate scope。compile()和link()的命名相当混乱。它们肯定是受编译队伍的启发而命名的。我可以看到相似点,不过一个编译器是传入一次,然后输出。而指令则是配置一次 HTML 元素,然后在之后的$scope对象改变时进行更新。compile()函数如果叫做create(),init()或者configure()也许会更好。这样可以表达出这个函数只会被调用一次的意思。而link()函数如果叫bind()或者render()也许会更好,能更好的表达出这样的意思,在指令绑定数据或者重绑定数据的时候,这个函数将会被调用。下面是一个完整的例子,演示了指令使用compile()和link()函数的:&div ng-controller=&MyController& & &userinfo &This will be replaced&/userinfo&&/div&&script& myapp = angular.module(&myapp&, []); myapp.directive('userinfo', function() {
var directive = {};
directive.restrict = 'E'; /* restrict this directive to elements */
pile = function(element, attributes) {
element.css(&border&, &1px solid #cccccc&);
var linkFunction = function($scope, element, attributes) {
element.html(&This is the new content: & + $scope.firstName);
element.css(&background-color&, &#ffff00&);
return linkF
}) myapp.controller(&MyController&, function($scope, $http) {
$scope.cssClass = &notificationDiv&;
$scope.firstName = &Jakob&;
$scope.doClick = function() {
console.log(&doClick() called&);
} });&/script&compile()函数设置 HTML 元素的 border 。它只执行一次,因为compile()函数只执行一次。link()替换 HTML 元素内容,并且把背景颜色设置为黄色。把设置 border 放在compile(), 把背景颜色放在link()没啥特别的理由。你可以把所有的操作都丢到compile(),或者都放到link()。如果都放到compile()它们只会被设置一次(你需要它们是常量的话)。如果放到了link(),它们会在每次 HTML 元素被绑到$scope的时候都发生变化。当你希望根据$scope中的数据来设置 boarder 和背景颜色的时候这非常有用。只设置 link() 函数有时候你的指令可能不需要compile()。你只需要用到link()。这种情况下,你可以直接设置指令定义对象中的link()函数。下面是一个对上面例子的修改,只用 link 函数:&div ng-controller=&MyController& &&userinfo &This will be replaced&/userinfo&&/div&&script&myapp = angular.module(&myapp&, []);myapp.directive('userinfo', function() { var directive = {}; directive.restrict = 'E'; /* restrict this directive to elements */ directive.link = function($scope, element, attributes) {
element.html(&This is the new content: & + $scope.firstName);
element.css(&background-color&, &#ffff00&); } })myapp.controller(&MyController&, function($scope, $http) { $scope.cssClass = &notificationDiv&; $scope.firstName = &Jakob&; $scope.doClick = function() { console.log(&doClick() called&); }});&/script&注意link()方法和之前例子中返回的link()是完全一样的。通过 Transclusion 封装元素的指令到目前为止,我们看到的所有例子,都是把匹配到的元素内容给替换为指令的指定内容,不管是通过 Javascript 也好或者 HTML 模板也好。不过如果遇到内容中有部分是开发者可以指定的内容的时候呢?比如说:&mytransclude&This is a transcluded directive {{firstName}}&/mytransclude&标记为&mytransclude&的元素,它的部分内容可以由开发者设置。因此,这部分 HTML 不应该被指令的 HTML 模板给替换。我们实际上是希望这部分 HTML 由 AngularJS 来处理的。这个处理叫做 “transclusion”。1为了能让 AngularJS 把这部分 HTML 放到指令内部处理,你必须设置指令定义对象的transclude属性为true。你还需要告诉 AngularJS,指令的 HTML 模板中哪一部分需要把 transcluded HTML 包含进来。你可以通过插入ng-transclude属性 (实际上,是一个指令) 到 HTML 模板的 HTML 元素中,标记你想要添加 transcluded HTML 的元素。下面是一个 AngularJS 指令,演示如何使用 transclusion:&mytransclude&This is a transcluded directive {{firstName}}&/mytransclude&&script&myapp = angular.module(&myapp&, []);myapp.directive('mytransclude', function() { var directive = {}; directive.restrict = 'E'; /* restrict this directive to elements */ directive.transclude = directive.template = &&div class='myTransclude' ng-transclude&&/div&&; });myapp.controller(&MyController&, function($scope, $http) { $scope.firstName = &Jakob&;});&/script&注意&mytransclude&元素内的 HTML。这部分 HTML 代码包含了内插指令{{firstName}}。我们希望 AngularJS 来为我们处理这部分 HTML,让内插指令执行。为了实现这个目的,我在指令定义对象中把transclude设置为true。我还在 HTML 模板中用到了ng-transclude属性。这个属性告诉 AngularJS 什么元素需要插入到 transcluded HTML。1: 说实话,我没看懂那个定义,说的太TM难懂了,而且我好不爽写代码没输出的教程。只好自己动手做做例子。我觉得其实应该是这样的,把目标元素内容作为一个整体,拿到 HTML 模板中来,添加到 ng-transclude 指定的标签下。这个处理,我觉得应该就是叫做 transcluded。比如说刚才的例子(有些 bug,自己修正一下),因为directive.transclude =,所以原来&mytransclude&元素内的 HTML:This is a transcluded directive {{firstName}}在激活指令 'mytransclude' 的时候,会被拿到 'mytransclude' 指令的模板中来,放到被ng-transclude指定的&&div class='myTransclude' ng-transclude&&/div&&中。于是最终输出的结果应该是:&mytransclude&&div class='myTransclude' ng-transclude&&span class=&ng-scope ng-binding&&This is a transcluded directive Jakob&/span&&/div&&/mytransclude&然后我又回去把翻译改了。现在感觉念起来顺口一点了。AngularJS学习笔记
   18:33 更新邹业盛
1. 关于AngularJS 是 Google 开源出来的一套 js 工具。下面简称其为
。这里只说它是“工具”,没说它是完整的“框架”,是因为它并不是定位于去完成一套框架要做的事。更重要的,是它给我们揭示了一种新的应用组织与开发方式。ng 最让我称奇的,是它的数据双向绑定。其实想想,我们一直在提数据与表现的分离,但是这里的“双向绑定”从某方面来说,是把数据与表现完全绑定在一起——数据变化,表现也变化。反之,表现变化了,内在的数据也变化。有过开发经验的人能体会到这种机制对于前端应用来说,是很有必要的,能带来维护上的巨大优势。当然,这里的绑定与提倡的分离并不是矛盾的。ng 可以和 jQuery 集成工作,事实上,如果没有 jQuery , ng 自己也做了一个轻量级的 jQuery ,主要实现了元素操作部分的 API 。关于 ng 的几点:对 IE 方面,它兼容 IE8 及以上的版本。与 jQuery 集成工作,它的一些对象与 jQuery 相关对象表现是一致的。使用 ng 时不要冒然去改变相关 DOM 的结构。2. 开始的例子我们从一个完整的例子开始认识 ng :1
&!DOCTYPE html& 2
&meta charset="utf-8" /& 5
&title&试验&/title& 7
&script type="text/javascript" src="jquery-1.8.3.js"&&/script& 9
&script type="text/javascript" src="angular.js"&&/script&10
&div ng-controller="BoxCtrl"&14
&div style="width: 100 height: 100 background-color:"15
ng-click="click()"&&/div&16
&p&{{ w }} x {{ h }}&/p&17
&p&W: &input type="text" ng-model="w" /&&/p&18
&p&H: &input type="text" ng-model="h" /&&/p&19
&script type="text/javascript" charset="utf-8"&23
var BoxCtrl = function($scope, $element){26
//$element 就是一个 jQuery 对象28
var e = $element.children().eq(0);29
$scope.w = e.width();30
$scope.h = e.height();31
$scope.click = function(){33
$scope.w = parseInt($scope.w) + 10;34
$scope.h = parseInt($scope.h) + 10;35
$scope.$watch('w',38
function(to, from){39
e.width(to);40
$scope.$watch('h',44
function(to, from){45
e.height(to);46
angular.bootstrap(document.documentElement);51
&/script&52
&/html&从上面的代码中,我们看到在通常的 HTML 代码当中,引入了一些标记,这些就是 ng 的模板机制,它不光完成数据渲染的工作,还实现了数据绑定的功能。同时,在 HTML 中的本身的 DOM 层级结构,被 ng 利用起来,直接作为它的内部机制中,上下文结构的判断依据。比如例子中 p 是 div 的子节点,那么 p 中的那些模板标记就是在 div 的 Ctrl 的作用范围之内。其它的,也同样写一些 js 代码,里面重要的是作一些数据的操作,事件的绑定定义等。这样,数据的变化就会和页面中的 DOM 表现联系起来。一旦这种联系建立起来,也即完成了我们所说的“双向绑定”。然后,这里说的“事件”,除了那些“点击”等通常的 DOM 事件之外,我们还更关注“数据变化”这个事件。最后,可以使用:angular.bootstrap(document.documentElement);来把整个页面驱动起来了。(你可以看到一个可被控制大小的红色方块)更完整的方法是定义一个 APP :1
&!DOCTYPE html& 2
&html ng-app="MyApp"& 3
&meta charset="utf-8" /& 5
&title&数据正向绑定&/title& 7
&script type="text/javascript" src="jquery-1.8.3.js"&&/script& 9
&script type="text/javascript" src="angular.js"&&/script&10
&div ng-controller="TestCtrl"&15
&input type="text" value="" id="a" /&16
&script type="text/javascript"&20
var TestCtrl = function(){21
console.log('ok');22
//angular.bootstrap(document.documentElement);25
angular.module('MyApp', [], function(){console.log('here')});26
&/script&27
&/html&这里说的一个 App 就是 ng 概念中的一个 Module 。对于 Controller 来说, 如果不想使用全局函数,也可以在 app 中定义:var app = angular.module('MyApp', [], function(){console.log('here')});
app.controller('TestCtrl',
function($scope){
console.log('ok');
);3. 依赖注入injector , 我从 ng 的文档中得知这个概念,之后去翻看源码时了解了一下这个机制的工作原理。感觉就是虽然与自己的所想仅差那么一点点,但就是这么一点点,让我感慨想象力之神奇。先看我们之前代码中的一处函数定义:var BoxCtrl = function($scope, $element){}在这个函数定义中,注意那两个参数: $scope , $element ,这是两个很有意思的东西。总的来说,它们是参数,这没什么可说的。但又不仅仅是参数——你换个名字代码就不能正常运行了。事实上,这两个参数,除了完成“参数”的本身任务之外,还作为一种语法糖完成了“依赖声明”的任务。本来这个函数定义,完整的写法应该像 AMD 声明一样,写成:var BoxCtrl = ['$scope', '$element', function(s, e){}];这样就很明显,表示有一个函数,它依赖于两个东西,然后这两个东西会依次作为参数传入。简单起见,就写成了一个函数定义原本的样子,然后在定义参数的名字上作文章,来起到依赖声明的作用。在处理时,通过函数对象的 toString() 方法可以知道这个函数定义代码的字符串表现形式,然后就知道它的参数是 $scope 和 $element 。通过名字判断出这是两个外部依赖,然后就去获取资源,最后把资源作为参数,调用定义的函数。所以,参数的名字是不能随便写的,这里也充分利用了 js 的特点来尽量做到“反省”了。在 Python 中受限于函数名的命名规则,写出来不太好看。不过也得利于反省机制,做到这点也很容易:# -*- coding: utf-8 -*-
def f(Ia, Ib):
print Ia, Ib
args = f.func_code.co_varnames
SRV_MAP = {
'Ia': '123',
'Ib': '456',
for a in args:
if a in SRV_MAP:
srv[a] = SRV_MAP[a]
f(**srv)4. 作用域这里提到的“作用域”的概念,是一个在范围上与 DOM 结构一致,数据上相对于某个 $scope 对象的属性的概念。我们还是从 HTML 代码上来入手:&div ng-controller="BoxCtrl"&
&div style="width: 100 height: 100 background-color:"
ng-click="click()"&
&p&{{ w }} x {{ h }}&/p&
&p&W: &input type="text" ng-model="w" /&&/p&
&p&H: &input type="text" ng-model="h" /&&/p&
&/div&上面的代码中,我们给一个 div 元素指定了一个 BoxCtrl ,那么, div 元素之内,就是 BoxCtrl 这个函数运行时, $scope 这个注入资源的控制范围。在代码中我们看到的 click() , w , h 这些东西,它们本来的位置对应于 $scope.click , $scope.w , $scope.h 。我们在后面的 js 代码中,也可以看到我们就是在操作这些变量。依赖于 ng 的数据绑定机制,操作变量的结果直接在页面上表现出来了。5. 数据绑定与模板我纠结了半天,“数据绑定”与“模板”这两个东西还真没办法分开来说。因为数据绑定需要以模板为载体,离开了模板,数据还绑个毛啊。ng 的一大特点,就是数据双向绑定。双向绑定是一体,为了描述方便,下面分别介绍。5.1. 数据-&模板数据到表现的绑定,主要是使用模板标记直接完成的:&p&{{ w }} x {{ h }}&/p&使用 {{ }} 这个标记,就可以直接引用,并绑定一个作用域内的变量。在实现上, ng 自动创建了一个 watcher 。效果就是,不管因为什么,如果作用域的变量发生了改变,我们随时可以让相应的页面表现也随之改变。我们可以看一个更纯粹的例子:&p id="test" ng-controller="TestCtrl"&{{ a }}&/p&
&script type="text/javascript"&
var TestCtrl = function($scope){
$scope.a = '123';
angular.bootstrap(document.documentElement);上面的例子在页面载入之后,我们可以在页面上看到 123 。这时,我们可以打开一个终端控制器,输入:$('#test').scope().a = '12345';
$('#test').scope().$digest();上面的代码执行之后,就可以看到页面变化了。对于使用 ng 进行的事件绑定,在处理函数中就不需要去关心 $digest() 的调用了。因为 ng 会自己处理。源码中,对于 ng 的事件绑定,真正的处理函数不是指定名字的函数,而是经过 $apply() 包装过的一个函数。这个 $apply() 做的一件事,就是调用根作用域 $rootScope 的 $digest() ,这样整个世界就清净了:&p id="test" ng-controller="TestCtrl" ng-click="click()"&{{ a }}&/p&
&script type="text/javascript" charset="utf-8"&
var TestCtrl = function($scope){
$scope.a = '123';
$scope.click = function(){
$scope.a = '456';
angular.bootstrap(document.documentElement);那个 click 函数的定义,绑定时变成了类似于:function(){
$scope.$apply(
function(){
$scope.click();
}这里的 $scope.$apply() 中做的一件事:$rootScope.$digest();5.2. 模板-&数据模板到数据的绑定,主要是通过 ng-model 来完成的:&input type="text" id="test" ng-controller="TestCtrl" ng-model="a" /&
&script type="text/javascript" charset="utf-8"&
var TestCtrl = function($scope){
$scope.a = '123';
}这时修改 input 中的值,然后再在控制终端中使用:$('#test').scope().a查看,发现变量 a 的值已经更改了。实际上, ng-model 是把两个方向的绑定都做了。它不光显示出变量的值,也把显示上的数值变化反映给了变量。这个在实现上就简单多了,只是绑定 change 事件,然后做一些赋值操作即可。不过 ng 里,还要区分对待不同的控件。5.3. 数据-&模板-&数据-&模板现在要考虑的是一种在现实中很普遍的一个需求。比如就是我们可以输入数值,来控制一个矩形的长度。在这里,数据与表现的关系是:长度数值保存在变量中变量显示于某个 input 中变量的值即是矩形的长度input 中的值变化时,变量也要变化input 中的值变化时,矩形的长度也要变化当然,要实现目的在这里可能就不止一种方案了。按照以前的做法,很自然地会想法,绑定 input 的 change 事件,然后去做一些事就好了。但是,我们前面提到过 ng-model 这个东西,利用它就可以在不手工处理 change 的条件下完成数据的展现需求,在此基础之上,我们还需要做的一点,就是把变化后的数据应用到矩形的长度之上。最开始,我们面对的应该是这样一个东西:&div ng-controller="TestCtrl"&
&div style="width: 100 height: 10 background-color: red"&&/div&
&input type="text" name="width" ng-model="width" /&
&script type="text/javascript" charset="utf-8"&
var TestCtrl = function($scope){
$scope.width = 100;
angular.bootstrap(document.documentElement);
&/script&我们从响应数据变化,但又不使用 change 事件的角度来看,可以这样处理宽度变化:var TestCtrl = function($scope, $element){
$scope.width = 100;
$scope.$watch('width',
function(to, from){
$element.children(':first').width(to);
}使用 $watch() 来绑定数据变化。当然,这种样式的问题,有更直接有效的手段, ng 的数据绑定总是让人惊异:&div ng-controller="TestCtrl"&
&div style="width: 10 height: 10 background-color: red" ng-style="style"&
&input type="text" name="width" ng-model="style.width" /&
&script type="text/javascript" charset="utf-8"&
var TestCtrl = function($scope){
$scope.style = {width: 100};
angular.bootstrap(document.documentElement);
&/script&6. 模板前面讲了数据绑定之后,现在可以单独讲讲模板了。作为一套能称之谓“模板”的系统,除了能干一些模板的常规的事之外(好吧,即使是常规的逻辑判断现在它也做不了的),配合作用域 $scope 和 ng 的数据双向绑定机制, ng 的模板系统就变得比较神奇了。6.1. 定义模板内容定义模板的内容现在有三种方式:在需要的地方直接写字符串外部文件使用 script 标签定义的“内部文件”第一种不需要多说。第二种和第三种都可以和 ng-include 一起工作,来引入一段模板。直接引入同域的外部文件作为模板的一部分:&div ng-include src="'tpl.html'"&
&div ng-include="'tpl.html'"&
&/div&注意, src 中的字符串会作为表达式处理(可以是 $scope 中的变量),所以,直接写名字的话需要使用引号。引入 script 定义的“内部文件”:&script type="text/ng-template" id="tpl"&
here, {{ 1 + 1 }}
&div ng-include src="'tpl'"&&/div&配合变量使用:&script type="text/ng-template" id="tpl"&
here, {{ 1 + 1 }}
&a ng-click="v='tpl'"&Load&/a&
&div ng-include src="v"&&/div&6.2. 内容渲染控制6.2.1. 重复 ng-repeat这算是唯一的一个控制标签么……,它的使用方法类型于:&div ng-controller="TestCtrl"&
&ul ng-repeat="member in obj_list"&
&li&{{ member }}&/li&
var TestCtrl = function($scope){
$scope.obj_list = [1,2,3,4];
}除此之外,它还提供了几个变量可供使用:$index 当前索引$first 是否为头元素$middle 是否为非头非尾元素$last 是否为尾元素&div ng-controller="TestCtrl"&
&ul ng-repeat="member in obj_list"&
&li&{{ $index }}, {{ member.name }}&/li&
var TestCtrl = function($scope){
$scope.obj_list = [{name: 'A'}, {name: 'B'}, {name: 'C'}];
}6.2.2. 赋值 ng-init这个指令可以在模板中直接赋值,它作用于 angular.bootstrap 之前,并且,定义的变量与 $scope 作用域无关。&div ng-controller="TestCtrl" ng-init="a=[1,2,3,4];"&
&ul ng-repeat="member in a"&
&li&{{ member }}&/li&
&/div&6.3. 节点控制6.3.1. 样式 ng-style可以使用一个结构直接表示当前节点的样式:&div ng-style="{width: 100, height: 100, backgroundColor: 'red'}"&
&/div&同样地,绑定一个变量的话,威力大了。6.3.2. 类 ng-class就是直接地设置当前节点的类,同样,配合数据绑定作用就大了:&div ng-controller="TestCtrl" ng-class="cls"&
&/div&ng-class-even 和 ng-class-odd 是和 ng-repeat 配合使用的:&ul ng-init="l=[1,2,3,4]"&
&li ng-class-odd="'odd'" ng-class-even="'even'" ng-repeat="m in l"&{{ m }}&/li&
&/ul&注意里面给的还是表示式,别少了引号。6.3.3. 显示和隐藏 ng-show ng-hide ng-switch前两个是控制 display 的指令:&div ng-show="true"&1&/div&
&div ng-show="false"&2&/div&
&div ng-hide="true"&3&/div&
&div ng-hide="false"&4&/div&后一个 ng-switch 是根据一个值来决定哪个节点显示,其它节点移除:&div ng-init="a=2"&
&ul ng-switch on="a"&
&li ng-switch-when="1"&1&/li&
&li ng-switch-when="2"&2&/li&
&li ng-switch-default&other&/li&
&/div&6.3.4. 其它属性控制ng-src 控制 src 属性:&img ng-src="{{ 'h' + 'ead.png' }}" /&ng-href 控制 href 属性:&a ng-href="{{ '#' + '123' }}"&here&/a&总的来说:ng-src src属性ng-href href属性ng-checked 选中状态ng-selected 被选择状态ng-disabled 禁用状态ng-multiple 多选状态ng-readonly 只读状态注意: 上面的这些只是单向绑定,即只是从数据到展示,不能反作用于数据。要双向绑定,还是要使用 ng-model 。6.4. 事件绑定事件绑定是模板指令中很好用的一部分。我们可以把相关事件的处理函数直接写在 DOM 中,这样做的最大好处就是可以从 DOM 结构上看出业务处理的形式,你知道当你点击这个节点时哪个函数被执行了。ng-changeng-clickng-dblclickng-mousedownng-mouseenterng-mouseleaveng-mousemoveng-mouseoverng-mouseupng-submit对于事件对象本身,在函数调用时可以直接使用 $event 进行传递:&p ng-click="click($event)"&点击&/p&
&p ng-click="click($event.target)"&点击&/p&6.5. 表单控件表单控件类的模板指令,最大的作用是它预定义了需要绑定的数据的格式。这样,就可以对于既定的数据进行既定的处理。6.5.1. formform 是核心的一个控件。 ng 对 form 这个标签作了包装。事实上, ng 自己的指令是叫 ng-form 的,区别在于, form 标签不能嵌套,而使用 ng-form 指令就可以做嵌套的表单了。form 的行为中依赖它里面的各个输入控制的状态的,在这里,我们主要关心的是 form 自己的一些方法和属性。从 ng 的角度来说, form 标签,是一个模板指令,也创建了一个 FormController 的实例。这个实例就提供了相应的属性和方法。同时,它里面的控件也是一个 NgModelController 实例。很重要的一点, form 的相关方法要生效,必须为 form 标签指定 name 和 ng-controller ,并且每个控件都要绑定一个变量。 form 和控件的名字,即是 $scope 中的相关实例的引用变量名。&form name="test_form" ng-controller="TestCtrl"&
&input type="text" name="a" required ng-model="a"
&span ng-click="see()"&{{ test_form.$valid }}&/span&
var TestCtrl = function($scope){
$scope.see = function(){
console.log($scope.test_form);
console.log($scope.test_form.a);
}除去对象的方法与属性, form 这个标签本身有一些动态类可以使用:ng-valid 当表单验证通过时的设置ng-invalid 当表单验证失败时的设置ng-pristine 表单的未被动之前拥有ng-dirty 表单被动过之后拥有form 对象的属性有:$pristine 表单是否未被动过$dirty 表单是否被动过$valid 表单是否验证通过$invalid 表单是否验证失败$error 表单的验证错误其中的 $error 对象包含有所有字段的验证信息,及对相关字段的 NgModelController 实例的引用。它的结构是一个对象, key 是失败信息, required , minlength 之类的, value 是对应的字段实例列表。注意,这里的失败信息是按序列取的一个。比如,如果一个字段既要求 required ,也要求 minlength ,那么当它为空时, $error 中只有 required 的失败信息。只输入一个字符之后, required 条件满足了,才可能有 minlength 这个失败信息。&form name="test_form" ng-controller="TestCtrl"&
&input type="text" name="a" required ng-model="a"
&input type="text" name="b" required ng-model="b" ng-minlength="2" /&
&span ng-click="see()"&{{ test_form.$error }}&/span&
var TestCtrl = function($scope){
$scope.see = function(){
console.log($scope.test_form.$error);
}6.5.2. inputinput 是数据的最主要入口。 ng 支持 HTML5 中的相关属性,同时对旧浏览器也做了兼容性处理。最重要的, input 的规则定义,是所属表单的相关行为的参照(比如表单是否验证成功)。input 控件的相关可用属性为:name 名字ng-model 绑定的数据required 是否必填ng-required 是否必填ng-minlength 最小长度ng-maxlength 最大长度ng-pattern 匹配模式ng-change 值变化时的回调&form name="test_form" ng-controller="TestCtrl"&
&input type="text" name="a" ng-model="a" required ng-pattern="/abc/" /&
&span ng-click="see()"&{{ test_form.$error }}&/span&
&/form&input 控件,它还有一些扩展,这些扩展有些有自己的属性:input type="number" 多了 number 错误类型,多了 max , min 属性。input type="url" 多了 url 错误类型。input type="email" 多了 email 错误类型。6.5.3. checkbox它也算是 input 的扩展,不过,它没有验证相关的东西,只有选中与不选中两个值:&form name="test_form" ng-controller="TestCtrl"&
&input type="checkbox" name="a" ng-model="a" ng-true-value="AA" ng-false-value="BB" /&
&span&{{ a }}&/span&
var TestCtrl = function($scope){
$scope.a = 'AA';
}两点:controller 要初始化变量值。controller 中的初始化值会关系到控件状态(双向绑定)。6.5.4. radio也是 input 的扩展。和 checkbox 一样,但它只有一个值了:&form name="test_form" ng-controller="TestCtrl"&
&input type="radio" name="a" ng-model="a" value="AA" /&
&input type="radio" name="a" ng-model="a" value="BB" /&
&span&{{ a }}&/span&
&/form&6.5.5. textarea同 input 。6.5.6. select这是一个比较牛B的控件。它里面的一个叫做 ng-options 的属性用于数据呈现。对于给定列表时的使用。最简单的使用方法, x for x in list :&form name="test_form" ng-controller="TestCtrl" ng-init="o=[0,1,2,3]; a=o[1];"&
&select ng-model="a" ng-options="x for x in o" ng-change="show()"&
&option value=""&可以加这个空值&/option&
&script type="text/javascript"&
var TestCtrl = function($scope){
$scope.show = function(){
console.log($scope.a);
angular.bootstrap(document.documentElement);
&/script&在 $scope 中, select 绑定的变量,其值和普通的 value 无关,可以是一个对象:&form name="test_form" ng-controller="TestCtrl"
ng-init="o=[{name: 'AA'}, {name: 'BB'}]; a=o[1];"&
&select ng-model="a" ng-options="x.name for x in o" ng-change="show()"&
&/form&显示与值分别指定, x.v as x.name for x in o :&form name="test_form" ng-controller="TestCtrl"
ng-init="o=[{name: 'AA', v: '00'}, {name: 'BB', v: '11'}]; a=o[1].v;"&
&select ng-model="a" ng-options="x.v as x.name for x in o" ng-change="show()"&
&/form&加入分组的, x.name group by x.g for x in o :&form name="test_form" ng-controller="TestCtrl"
ng-init="o=[{name: 'AA', g: '00'}, {name: 'BB', g: '11'}, {name: 'CC', g: '00'}]; a=o[1];"&
&select ng-model="a" ng-options="x.name group by x.g for x in o" ng-change="show()"&
&/form&分组了还分别指定显示与值的, x.v as x.name group by x.g for x in o :&form name="test_form" ng-controller="TestCtrl" ng-init="o=[{name: 'AA', g: '00', v: '='}, {name: 'BB', g: '11', v: '+'}, {name: 'CC', g: '00', v: '!'}]; a=o[1].v;"&
&select ng-model="a" ng-options="x.v as x.name group by x.g for x in o" ng-change="show()"&
&/form&如果参数是对象的话,基本也是一样的,只是把遍历的对象改成 (key, value) :&form name="test_form" ng-controller="TestCtrl" ng-init="o={a: 0, b: 1}; a=o.a;"&
&select ng-model="a" ng-options="k for (k, v) in o" ng-change="show()"&
&form name="test_form" ng-controller="TestCtrl"
ng-init="o={a: {name: 'AA', v: '00'}, b: {name: 'BB', v: '11'}}; a=o.a.v;"&
&select ng-model="a" ng-options="v.v as v.name for (k, v) in o" ng-change="show()"&
&form name="test_form" ng-controller="TestCtrl"
ng-init="o={a: {name: 'AA', v: '00', g: '=='}, b: {name: 'BB', v: '11', g: '=='}}; a=o.a;"&
&select ng-model="a" ng-options="v.name group by v.g for (k, v) in o" ng-change="show()"&
&form name="test_form" ng-controller="TestCtrl"
ng-init="o={a: {name: 'AA', v: '00', g: '=='}, b: {name: 'BB', v: '11', g: '=='}}; a=o.a.v;"&
&select ng-model="a" ng-options="v.v as v.name group by v.g for (k, v) in o" ng-change="show()"&
&/form&7. 模板中的过滤器这里说的过滤器,是用于对数据的格式化,或者筛选的函数。它们可以直接在模板中通过一种语法使用。对于常用功能来说,是很方便的一种机制。多个过滤器之间可以直接连续使用。7.1. 排序 orderByorderBy 是一个排序用的过滤器标签。它可以像 sort 函数那样支持一个排序函数,也可以简单地指定一个属性名进行操作:&div ng-controller="TestCtrl"&
{{ data | orderBy: 'age' }} &br /&
{{ data | orderBy: '-age' }} &br /&
{{ data | orderBy: '-age' | limitTo: 2 }} &br /&
{{ data | orderBy: ['-age', 'name'] }} &br /&
&script type="text/javascript"&
var TestCtrl = function($scope){
$scope.data = [
{name: 'B', age: 4},
{name: 'A', age: 1},
{name: 'D', age: 3},
{name: 'C', age: 3},
angular.bootstrap(document.documentElement);
&/script&7.2. 过滤列表 filterfilter 是一个过滤内容的标签。如果参数是一个字符串,则列表成员中的任意属性值中有这个字符串,即为满足条件(忽略大小写):&div ng-controller="TestCtrl"&
{{ data | filter: 'b' }} &br /&
{{ data | filter: '!B' }} &br /&
&script type="text/javascript"&
var TestCtrl = function($scope){
$scope.data = [
{name: 'B', age: 4},
{name: 'A', age: 1},
{name: 'D', age: 3},
{name: 'C', age: 3},
angular.bootstrap(document.documentElement);
&/script&可以使用对象,来指定属性名, $ 表示任意属性:{{ data | filter: {name: 'A'} }} &br /&
{{ data | filter: {$: '3'} }} &br /&
{{ data | filter: {$: '!3'} }} &br /&自定义的过滤函数也支持:&div ng-controller="TestCtrl"&
{{ data | filter: f }} &br /&
&script type="text/javascript"&
var TestCtrl = function($scope){
$scope.data = [
{name: 'B', age: 4},
{name: 'A', age: 1},
{name: 'D', age: 3},
{name: 'C', age: 3},
$scope.f = function(e){
return e.age & 2;
angular.bootstrap(document.documentElement);
&/script&7.3. 其它时间戳格式化 date :&div ng-controller="TestCtrl"&
{{ a | date: 'yyyy-MM-dd HH:mm:ss' }}
&script type="text/javascript"&
var TestCtrl = function($scope){
$scope.a = ((new Date().valueOf()));
angular.bootstrap(document.documentElement);
&/script&列表截取 limitTo ,支持正负数:{{ [1,2,3,4,5] | limitTo: 2 }}
{{ [1,2,3,4,5] | limitTo: -3 }}大小写 lowercase , uppercase :{{ 'abc' | uppercase }}
{{ 'Abc' | lowercase }}7.4. 例子:表头排序1
&div ng-controller="TestCtrl"& 2
&th ng-click="f='name'; rev=!rev"&名字&/th& 5
&th ng-click="f='age'; rev=!rev"&年龄&/th& 6
&tr ng-repeat="o in data | orderBy: f : rev"& 9
&td&{{ o.name }}&/td&10
&td&{{ o.age }}&/td&11
&/table&13
&script type="text/javascript"&16
var TestCtrl = function($scope){17
$scope.data = [18
{name: 'B', age: 4},
{name: 'A', age: 1},
{name: 'D', age: 3},
{name: 'C', age: 3},
angular.bootstrap(document.documentElement);26
&/script&7.5. 例子:搜索&div ng-controller="TestCtrl" ng-init="s=data[0]. q=''"&
&span&查找:&/span& &input type="text" ng-model="q" /&
&select ng-multiple="true" ng-model="s"
ng-options="o.name as o.name + '(' + o.age + ')' for o in data | filter: {name: q} | orderBy: ['age', 'name'] "&
&script type="text/javascript"&
var TestCtrl = function($scope){
$scope.data = [
{name: 'B', age: 4},
{name: 'A', age: 1},
{name: 'D', age: 3},
{name: 'C', age: 3},
angular.bootstrap(document.documentElement);
&/script&8. 锚点路由准确地说,这应该叫对 hashchange 事件的处理吧。就是指 URL 中的锚点部分发生变化时,触发预先定义的业务逻辑。比如现在是 /test#/x ,锚点部分的值为 # 后的 /x ,它就对应了一组处理逻辑。当这部分变化时,比如变成了 /test#/t ,这时页面是不会刷新的,但是它可以触发另外一组处理逻辑,来做一些事,也可以让页面发生变化。这种机制对于复杂的单页面来说,无疑是一种强大的业务切分手段。就算不是复杂的单页面应用,在普通页面上善用这种机制,也可以让业务逻辑更容易控制。ng 提供了完善的锚点路由功能,虽然目前我觉得相当重要的一个功能还有待完善(后面会说),但目前这功能的几部分内容,已经让我思考了很多种可能性了。ng 中的锚点路由功能是由几部分 API 共同完成的一整套方案。这其中包括了路由定义,参数定义,业务处理等。8.1. 路由定义要使用锚点路由功能,需要在先定义它。目前,对于定义的方法,我个人只发现在“初始化”阶段可以通过 $routeProvider 这个服务来定义。在定义一个 app 时可以定义锚点路由:&html ng-app="ngView"&
&div ng-view&&/div&
&script type="text/javascript"&
angular.module('ngView', [],
function($routeProvider){
$routeProvider.when('/test',
template: 'test',
&/script&首先看 ng-view 这个 directive ,它是一个标记“锚点作用区”的指令。目前页面上只能有一个“锚点作用区”。有人已经提了,“多个可命名”的锚点作用区的代码到官方,但是目前官方还没有接受合并,我觉得多个作用区这个功能是很重要的,希望下个发布版中能有。锚点作用区的功能,就是让锚点路由定义时的那些模板, controller 等,它们产生的 HTML 代码放在作用区内。比如上面的代码,当你刚打开页面时,页面是空白的。你手动访问 /#/test 就可以看到页面上出现了 'test' 的字样。在 angular.bootstrap() 时也可以定义:angular.bootstrap(document.documentElement, [
function($routeProvider){
$routeProvider.when('/test',
template: 'test'
]);8.2. 参数定义在作路由定义时,可以匹配一个规则,规则中可以定义路径中的某些部分作为参数之用,然后使用 $routeParams 服务获取到指定参数。比如 /#/book/test 中, test 作为参数传入到 controller 中:&div ng-view&&/div&
&script type="text/javascript"&
angular.module('ngView', [],
function($routeProvider){
$routeProvider.when('/book/:title',
template: '{{ title }}',
controller: function($scope, $routeParams){
$scope.title = $routeParams.
&/script&访问: /#/book/test不需要预定义模式,也可以像普通 GET 请求那样获取到相关参数:angular.module('ngView', [],
function($routeProvider){
$routeProvider.when('/book',
template: '{{ title }}',
controller: function($scope, $routeParams){
$scope.title = $routeParams.
);访问: /#/book?title=test8.3. 业务处理简单来说,当一个锚点路由定义被匹配时,会根据模板生成一个 $scope ,同时相应的一个 controller 就会被触发。最后模板的结果会被填充到 ng-view 中去。从上面的例子中可以看到,最直接的方式,我们可以在模板中双向绑定数据,而数据的来源,在 controller 中控制。在 controller 中,又可以使用到像 $scope , $routeParams 这些服务。这里先提一下另外一种与锚点路由相关的服务, $route 。这个服务里锚点路由在定义时,及匹配过程中的信息。比如我们搞怪一下:angular.module('ngView', [],
function($routeProvider){
$routeProvider.when('/a',
template: '{{ title }}',
controller: function($scope){
$scope.title = 'a';
$routeProvider.when('/b',
template: '{{ title }}',
controller: function($scope, $route){
console.log($route);
$route.routes['/a'].controller($scope);
);回到锚点定义的业务处理中来。我们可以以字符串形式写模板,也可以直接引用外部文件作为模板:angular.module('ngView', [],
function($routeProvider){
$routeProvider.when('/test',
templateUrl: 'tpl.html',
controller: function($scope){
$scope.title = 'a';
);tpl.html 中的内容是:{{ title }}这样的话,模板可以预定义,也可以很复杂了。现在暂时忘了模板吧,因为前面提到的,当前 ng-view 不能有多个的限制,模板的渲染机制局限性还是很大的。不过,反正会触发一个 controller ,那么在函数当中我们可以尽量地干自己喜欢的事:angular.module('ngView', [],
function($routeProvider){
$routeProvider.when('/test',
template: '{{}}',
controller: function(){
$('div').first().html('&b&OK&/b&');
);那个空的 template 不能省,否则 controller 不会被触发。9. 定义模板变量标识标签由于下面涉及动态内容,所以我打算起一个后端服务来做。但是我发现我使用的 Tornado 框架的模板系统,与 ng 的模板系统,都是使用 {{ }} 这对符号来定义模板表达式的,这太悲剧了,不过幸好 ng 已经提供了修改方法:angular.bootstrap(document.documentElement,
[function($interpolateProvider){
$interpolateProvider.startSymbol('[[');
$interpolateProvider.endSymbol(']]');
}]);使用 $interpolateProvider 服务即可。10. AJAXng 提供了基本的 AJAX 封装,你直接面对 promise 对象,使用起来还是很方便的。10.1. HTTP请求基本的操作由 $http 服务提供。它的使用很简单,提供一些描述请求的参数,请求就出去了,然后返回一个扩充了 success 方法和 error 方法的 promise 对象(下节介绍),你可以在这个对象中添加需要的回调函数。var TestCtrl = function($scope, $http){
var p = $http({
method: 'GET',
url: '/json'
p.success(function(response, status, headers, config){
$scope.name = response.
}$http 接受的配置项有:method 方法url 路径params GET请求的参数data post请求的参数headers 头transformRequest 请求预处理函数transformResponse 响应预处理函数cache 缓存timeout 超时毫秒,超时的请求会被取消withCredentials 跨域安全策略的一个东西其中的 transformRequest 和 transformResponse 及 headers 已经有定义的,如果自定义则会覆盖默认定义:1
var $config = this.defaults = { 2
// transform incoming response data 3
transformResponse: [function(data) { 4
if (isString(data)) { 5
// strip json vulnerability protection prefix 6
data = data.replace(PROTECTION_PREFIX, ''); 7
if (JSON_START.test(data) && JSON_END.test(data)) 8
data = fromJson(data, true); 9
// transform outgoing request data14
transformRequest: [function(d) {15
return isObject(d) && !isFile(d) ? toJson(d) :16
// default headers19
headers: {20
common: {21
'Accept': 'application/json, text/plain, */*',22
'X-Requested-With': 'XMLHttpRequest'23
post: {'Content-Type': 'application/charset=utf-8'},25
{'Content-Type': 'application/charset=utf-8'}26
};注意它默认的 POST 方法出去的 Content-Type对于几个标准的 HTTP 方法,有对应的 shortcut :$http.delete(url, config)$http.get(url, config)$http.head(url, config)$http.jsonp(url, config)$http.post(url, data, config)$http.put(url, data, config)注意其中的 JSONP 方法,在实现上会在页面中添加一个 script 标签,然后放出一个 GET 请求。你自己定义的,匿名回调函数,会被 ng 自已给一个全局变量。在定义请求,作为 GET 参数,你可以使用 JSON_CALLBACK 这个字符串来暂时代替回调函数名,之后 ng 会为你替换成真正的函数名:var p = $http({
method: 'JSONP',
url: '/json',
params: {callback: 'JSON_CALLBACK'}
p.success(function(response, status, headers, config){
console.log(response);
$scope.name = response.
});$http 有两个属性:defaults 请求的全局配置pendingRequests 当前的请求队列状态$http.defaults.transformRequest = function(data){console.log('here');}
console.log($http.pendingRequests);10.2. 广义回调管理和其它框架一样, ng 提供了广义的异步回调管理的机制。 $http 服务是在其之上封装出来的。这个机制就是 ng 的 $q 服务。不过 ng 的这套机制总的来说实现得比较简单,按官方的说法,够用了。使用的方法,基本上是:通过 $q 服务得到一个 deferred 实例通过 deferred 实例的 promise 属性得到一个 promise 对象promise 对象负责定义回调函数deferred 实例负责触发回调var TestCtrl = function($q){
var defer = $q.defer();
var promise = defer.
promise.then(function(data){console.log('ok, ' + data)},
function(data){console.log('error, ' + data)});
//defer.reject('xx');
defer.resolve('xx');
}了解了上面的东西,再分别看 $q , deferred , promise 这三个东西。10.2.1. $q$q 有四个方法:$q.all() 合并多个 promise ,得到一个新的 promise$q.defer() 返回一个 deferred 对象$q.reject() 包装一个错误,以使回调链能正确处理下去$q.when() 返回一个 promise 对象$q.all() 方法适用于并发场景很合适:var TestCtrl = function($q, $http){
var p = $http.get('/json', {params: {a: 1}});
var p2 = $http.get('/json', {params: {a: 2}});
var all = $q.all([p, p2]);
p.success(function(res){console.log('here')});
all.then(function(res){console.log(res[0])});
}$q.reject() 方法是在你捕捉异常之后,又要把这个异常在回调链中传下去时使用:要理解这东西,先看看 promise 的链式回调是如何运作的,看下面两段代码的区别:var defer = $q.defer();
var p = defer.
function(data){return 'xxx'}
function(data){console.log(data)}
defer.resolve('123');var defer = $q.defer();
var p = defer.
var p2 = p.then(
function(data){return 'xxx'}
function(data){console.log(data)}
defer.resolve('123');从模型上看,前者是“并发”,后者才是“链式”。而 $q.reject() 的作用就是触发后链的 error 回调:var defer = $q.defer();
var p = defer.
function(data){return data},
function(data){return $q.reject(data)}
function(data){console.log('ok, ' + data)},
function(data){console.log('error, ' + data)}
defer.reject('123');最后的 $q.when() 是把数据封装成 promise 对象:var p = $q.when(0, function(data){return data},
function(data){return data});
function(data){console.log('ok, ' + data)},
function(data){console.log('error, ' + data)}
);10.2.2. deferreddeferred 对象有两个方法一个属性。promise 属性就是返回一个 promise 对象的。resolve() 成功回调reject() 失败回调var defer = $q.defer();
var promise = defer.
promise.then(function(data){console.log('ok, ' + data)},
function(data){console.log('error, ' + data)});
//defer.reject('xx');
defer.resolve('xx');10.2.3. promisepromise 对象只有 then() 一个方法,注册成功回调函数和失败回调函数,再返回一个 promise 对象,以用于链式调用。11. 工具函数11.1. 上下文绑定angular.bind 是用来进行上下文绑定,参数动态绑定的工具函数。var f = angular.bind({a: 'xx'},
function(){
console.log(this.a);
f();参数动态绑定:var f = function(x){console.log(x)}
angular.bind({}, f, 'x')();11.2. 对象处理对象复制: angular.copy()var a = {'x': '123'};
var b = angular.copy(a);
a.x = '456';
console.log(b);对象聚合: angular.extend()var a = {'x': '123'};
var b = {'xx': '456'};
angular.extend(b, a);
console.log(b);空函数: angular.noop()大小写转换: angular.lowercase() 和 angular.uppercase()JSON转换: angular.fromJson() 和 angular.toJson()遍历: angular.forEach() ,支持列表和对象:var l = {a: '1', b: '2'};
angular.forEach(l, function(v, k){console.log(k + ': ' + v)});
var l = ['a', 'b', 'c'];
angular.forEach(l, function(v, i, o){console.log(v)});
var context = {'t': 'xx'};
angular.forEach(l, function(v, i, o){console.log(this.t)}, context);11.3. 类型判定angular.isArrayangular.isDateangular.isDefinedangular.isElementangular.isFunctionangular.isNumberangular.isObjectangular.isStringangular.isUndefined12. 其它服务12.1. 日志ng 提供 $log 这个服务用于向终端输出相关信息:error()info()log()warn()var TestCtrl = function($log){
$log.error('error');
$('info');
$log.log('log');
$log.warn('warn');
}12.2. 缓存ng 提供了一个简单封装了缓存机制 $cacheFactory ,可以用来作为数据容器:var TestCtrl = function($scope, $cacheFactory){
$scope.cache = $cacheFactory('s_' + $scope.$id, {capacity: 3});
$scope.show = function(){
console.log($scope.cache.get('a'));
console.log($());
$scope.set = function(){
$scope.cache.put((new Date()).valueOf(), 'ok');
}调用时,第一个参数是 id ,第二个参数是配置项,目前支持 capacity 参数,用以设置缓存能容留的最大条目数。超过这个个数,则自动清除较旧的条目。缓存实例的方法:info() 获取 id , size 信息put(k, v) 设置新条目get(k) 获取条目remove(k) 删除条目removeAll() 删除所有条目destroy() 删除对本实例的引用$http 的调用当中,有一个 cache 参数,值为 true 时为自动维护的缓存。值也可以设置为一个 cache 实例。12.3. 计时器$timeout 服务是 ng 对 window.setTimeout() 的封装,它使用 promise 统一了计时器的回调行为:var TestCtrl = function($timeout){
var p = $timeout(function(){console.log('haha')}, 5000);
p.then(function(){console.log('x')});
//$timeout.cancel(p);
}使用 $timeout.cancel() 可以取消计时器。12.4. 表达式函数化$parse 这个服务,为 js 提供了类似于 Python 中 @property 的能力:var TestCtrl = function($scope, $parse){
$scope.get_name = $parse('name');
$scope.show = function(){console.log($scope.get_name($scope))}
$scope.set = function(){$scope.name = '123'}
}$parse 返回一个函数,调用这个函数时,可以传两个参数,第一个作用域,第二个是变量集,后者常用于覆盖前者的变量:var get_name = $parse('name');
var r = get_name({name: 'xx'}, {name: 'abc'});
console.log(r);$parse 返回的函数,也提供了相应的 assign 功能,可以为表达式赋值(如果可以的话):var get_name = $parse('name');
var set_name = get_name.
var r = get_name({name: 'xx'}, {name: 'abc'});
console.log(r);
var s = {}
set_name(s, '123');
var r = get_name(s);
console.log(r);12.5. 模板单独使用ng 中的模板是很重要,也很强大的一个机制,自然少不了单独运用它的方法。不过,即使是单独使用,也是和 DOM 紧密相关的程度:定义时必须是有 HTML 标签包裹的,这样才能创建 DOM 节点渲染时必须传入 $scope之后使用 $compile 就可以得到一个渲染好的节点对象了。当然, $compile 还要做其它一些工作,指令处理什么的。var TestCtrl = function($scope, $element,$compile){
$scope.a = '123';
$scope.set = function(){
var tpl = $compile('&p&hello {{ a }}&/p&');
var e = tpl($scope);
$element.append(e);
}13. 自定义模块和服务13.1. 模块和服务的概念与关系总的来说,模块是组织业务的一个框框,在一个模块当中定义多个服务。当你引入了一个模块的时候,就可以使用这个模块提供的一种或多种服务了。比如 AngularJS 本身的一个默认模块叫做 ng ,它提供了 $http , $q 等等服务。服务只是模块提供的多种机制中的一种,其它的还有命令( directive ),过滤器( filter ),及其它配置信息。然后在额外的 js 文件中有一个附加的模块叫做 ngResource , 它提供了一个 $resource 服务。定义时,我们可以在已有的模块中新定义一个服务,也可以先新定义一个模块,然后在新模块中定义新服务。使用时,服务是需要显式地的声明依赖(引入)关系的,而服务则可以让 ng 自动地做注入,然后直接使用。13.2. 定义模块定义模块的方法是使用 angular.module 。调用时声明了对其它模块的依赖,并定义了“初始化”函数。var my_module = angular.module('MyModule', [], function(){
console.log('here');
});这段代码定义了一个叫做 MyModule 的模块, my_module 这个引用可以在接下来做其它的一些事,比如定义服务。13.3. 定义服务服务本身是一个任意的对象。但是 ng 提供服务的过程涉及它的依赖注入机制。在这里呢,就要先介绍一下叫 provider 的东西。简单来说, provider 是被“注入控制器”使用的一个对象,注入机制通过调用一个 provider 的 $get() 方法,把得到的东西作为参数进行相关调用(比如把得到的服务作为一个 Controller 的参数)。在这里“服务”的概念就比较不明确,对使用而言,服务仅指 $get() 方法返回的东西,但是在整体机制上,服务又要指提供了 $get() 方法的整个对象。//这是一个provider
var pp = function(){
this.$get = function(){
return {'haha': '123'};
//我在模块的初始化过程当中, 定义了一个叫 PP 的服务
var app = angular.module('Demo', [], function($provide){
$provide.provider('PP', pp);
//PP服务实际上就是 pp 这个 provider 的 $get() 方法返回的东西
app.controller('TestCtrl',
function($scope, PP){
console.log(PP);
);上面的代码是一种定义服务的方法,当然, ng 还有相关的 shortcut, ng 总有很多 shortcut 。第一个是 factory 方法,由 $provide 提供, module 的 factory 是一个引用,作用一样。这个方法直接把一个函数当成是一个对象的 $get() 方法,这样你就不用显式地定义一个 provider 了:var app = angular.module('Demo', [], function($provide){
$provide.factory('PP', function(){
return {'hello': '123'};
app.controller('TestCtrl', function($scope, PP){ console.log(PP) });在 module 中使用:var app = angular.module('Demo', [], function(){ });
app.factory('PP', function(){return {'abc': '123'}});
app.controller('TestCtrl', function($scope, PP){ console.log(PP) });第二个是 service 方法,也是由 $provide 提供, module 中有对它的同名引用。 service 和 factory 的区别在于,前者是要求提供一个“构造方法”,后者是要求提供 $get() 方法。意思就是,前者一定是得到一个 object ,后者可以是一个数字或字符串。它们的关系大概是:var app = angular.module('Demo', [], function(){ });
app.service = function(name, constructor){
app.factory(name, function(){
return (new constructor());
}这里插一句,js 中 new 的作用,以 new a() 为例,过程相当于:创建一个空对象 obj把 obj 绑定到 a 函数的上下文当中(即 a 中的 this 现在指向 obj )执行 a 函数返回 objservice 方法的使用就很简单了:var app = angular.module('Demo', [], function(){ });
app.service('PP', function(){
this.abc = '123';
app.controller('TestCtrl', function($scope, PP){ console.log(PP) });13.4. 引入模块并使用服务结合上面的“定义模块”和“定义服务”,我们可以方便地组织自己的额外代码:angular.module('MyModule', [], function($provide){
$provide.factory('S1', function(){
return 'I am S1';
$provide.factory('S2', function(){
return {see: function(){return 'I am S2'}}
var app = angular.module('Demo', ['MyModule'], angular.noop);
app.controller('TestCtrl', function($scope, S1, S2){
console.log(S1)
console.log(S2.see())
});14. 附加模块 ngResource14.1. 使用引入与整体概念ngResource 这个是 ng 官方提供的一个附加模块。附加的意思就是,如果你打算用它,那么你需要引入一人单独的 js 文件,然后在声明“根模块”时注明依赖的 ngResource 模块,接着就可以使用它提供的 $resource 服务了。完整的过程形如:&!DOCTYPE html&
&html ng-app="Demo"&
&meta charset="utf-8" /&
&title&AngularJS&/title&
&script type="text/javascript" src="/ajax/libs/angularjs/1.0.3/angular.min.js"&&/script&
&script type="text/javascript" src="/ajax/libs/angularjs/1.0.3/angular-resource.js"&&/script&
&div ng-controller="TestCtrl"&&/div&
&script type="text/javascript" charset="utf-8"&
var app = angular.module('Demo', ['ngResource'], angular.noop);
app.controller('TestCtrl', function($scope, $resource){
console.log($resource);
&/html&$resource 服务,整体上来说,比较像是使用类似 ORM 的方式来包装了 AJAX 调用。区别就是 ORM 是操作数据库,即拼出 SQL 语句之后,作 execute 方法调用。而 $resource 的方式是构造出 AJAX 请求,然后发出请求。同时,AJAX 请求是需要回调处理的,这方面, $resource 的机制可以使你在一些时候省掉回调处理,当然,是否作回调处理在于业务情形及容错需求了。使用上 $resource 分成了“类”与“实例”这两个层面。一般地,类的方法调用就是直观的调用形式,通常会返回一个对象,这个对象即为“实例”。“实例”贯穿整个服务的使用过程。“实例”的数据是填充方式,即因为异步关系,回调函数没有执行时,实例已经存在,只是可能它还没有相关数据,回调执行之后,相关数据被填充到实例对象当中。实例的方法一般就是在类方法名前加一个 $ ,调用上,根据定义,实例数据可能会做一些自动的参数填充,这点是区别实例与类的调用上的不同。好吧,上面这些话可能需要在看了接下来的内容之后再回过来理解。14.2. 基本定义就像使用 ORM 一般要先定义 Model 一样,使用 $resource 需要先定义“资源”,也就是先定义一些 HTTP 请求。在业务场景上,我们假设为,我们需要操作“书”这个实体,包括创建create,获取详情read,修改update,删除delete,批量获取multi,共五个操作方法。实体属性有:唯一标识id,标题title,作者author。我们把这些操作定义成 $resource 的资源:var app = angular.module('Demo', ['ngResource'], angular.noop);
app.controller('BookCtrl', function($scope, $resource){
var actions = {
create: {method: 'POST', params: {_method: 'create'}},
read: {method: 'POST', params: {_method: 'read'}},
update: {method: 'POST', params: {_method: 'update'}},
delete: {method: 'POST', params: {_method: 'delete'}},
multi: {method: 'POST', params: {_method: 'multi'}}
var Book = $resource('/book', {}, actions);
});定义是使用使用 $resource 这个函数就可以了,它接受三个参数:url默认的params(这里的 params 即是 GET 请求的参数,POST 的参数单独叫做“postData”)方法映射方法映射是以方法名为 key ,以一个对象为 value ,这个 value 可以有三个成员:method, 请求方法,'GET', 'POST', 'PUT', 'DELETE' 这些params, 默认的 GET 参数isArray, 返回的数据是不是一个列表14.3. 基本使用在定义了资源之后,我们看如果使用这些资源,发出请求:var book = Book.read({id: '123'}, function(response){
console.log(response);
});这里我们进行 Book 的“类”方法调用。在方法的使用上,根据官方文档:HTTP GET "class" actions: Resource.action([parameters], [success], [error])
non-GET "class" actions: Resource.action([parameters], postData, [success], [error])
non-GET instance actions: instance.$action([parameters], [success], [error])我们这里是第二种形式,即类方法的非 GET 请求。我们给的参数会作为 postData 传递。如果我们需要 GET 参数,并且还需要一个错误回调,那么:var book = Book.read({get: 'haha'}, {id: '123'},
function(response){
console.log(response);
function(error){
console.log(error);
);调用之后,我们会立即得到的 book ,它是 Book 类的一个实例。这里所谓的实例,实际上就是先把所有的 action 加一个 $ 前缀放到一个空对象里,然后把发出的参数填充进去。等请求返回了,把除 action 以外的成员删除掉,再把请求返回的数据填充到这个对象当中。所以,如果我们这样:var book = Book.read({id: '123'}, function(response){
console.log(book);
console.log(book)就能看到 book 实例的变化过程了。现在我们得到一个真实的实例,看一下实例的调用过程://响应的数据是 {result: 0, msg: '', obj: {id: 'xxx'}}
var book = Book.create({title: '测试标题', author: '测试作者'}, function(response){
console.log(book);
});可以看到,在请求回调之后, book 这个实例的成员已经被响应内容填充了。但是这里有一个问题,我们返回的数据,并不适合一个 book 实例。格式先不说,它把 title 和 author 这些信息都丢了(因为响应只返回了 id )。如果仅仅是格式问题,我们可以通过配置 $http 服务来解决( AJAX 请求都要使用 $http 服务的):$http.defaults.transformResponse = function(data){return angular.fromJson(data).obj};当然,我们也可以自己来解决一下丢信息的问题:var p = {title: '测试标题', author: '测试作者'};
var book = Book.create(p, function(response){
angular.extend(book, p);
console.log(book);
});不过,始终会有一些不方便了。比较正统的方式应该是调节服务器端的响应,让服务器端也具有和前端一样的实例概念,返回的是完整的实例信息。即使这样,你也还要考虑格式的事。现在我们得到了一个真实的 book 实例了,带有 id 信息。我们尝试一下实例的方法调用,先回过去头看一下那三种调用形式,对于实例只有第三种形式:non-GET instance actions: instance.$action([parameters], [success], [error])首先解决一个疑问,如果一个实例是进行一个 GET 的调用会怎么样?没有任何问题,这当然没有任何问题的,形式和上面一样。如何实例是做 POST 请求的话,从形式上看,我们无法控制请求的 postData ?是的,所有的 POST 请求,其 postData 都会被实例数据自动填充,形式上我们只能控制 params 。所以,如果是在做修改调用的话:book.$update({title: '新标题', author: '测试作者'}, function(response){
console.log(book);
});这样是没有意义的并且错误的。因为要修改的数据只是作为 GET 参数传递了,而 postData 传递的数据就是当前实例的数据,并没有任何修改。正确的做法:book.title = '新标题'
book.$update(function(response){
console.log(book);
});显然,这种情况下,回调都可以省了:book.title = '新标题'
book.$update();14.4. 定义和使用时的占位量两方面。一是在定义时,在其 URL 中可以使用变量引用的形式(类型于定义锚点路由时那样)。第二时定义默认 params ,即 GET 参数时,可以定义为引用 postData 中的某变量。比如我们这样改一下:var Book = $resource('/book/:id', {}, actions);
var book = Book.read({id: '123'}, {}, function(response){
console.log(response);
});在 URL 中有一个 :id ,表示对 params 中 id 这个变量的引用。因为 read 是一个 POST 请求,根据调用形式,第一个参数是 params ,第二个参数是 postData 。这样的调用结果就是,我们会发一个 POST 请求到如下地址, postData 为空:/book/123?_method=read再看默认的 params 中引用 postData 变量的形式:var Book = $resource('/book', {id: '@id'}, actions);
var book = Book.read({title: 'xx'}, {id: '123'}, function(response){
console.log(response);
});这样会出一个 POST 请求, postData 内容中有一个 id 数据,访问的 URL 是:/book?_method=read&id=123&title=xx这两个机制也可以联合使用:var Book = $resource('/book/:id', {id: '@id'}, actions);
var book = Book.read({title: 'xx'}, {id: '123'}, function(response){
console.log(response);
});结果就是出一个 POST 请求, postData 内容中有一个 id 数据,访问的 URL 是:/book/123?_method=read&title=xx14.5. 实例ngResource 要举一个实例是比较麻烦的事。因为它必须要一个后端来支持,这里如果我用 Python 写一个简单的后端,估计要让这个后端跑起来对很多人来说都是问题。所以,我在几套公共服务的 API 中纠结考察了一番,最后使用
的 API 来做了一个简单的,可用的例子。例子见:
(可以直接下载看源码)先说一下 API 的情况。这里的请求调用全是跨域的,所以交互上全部是使用了 JSONP 的形式。 API 的使用有使用签名认证机制,嗯, js 中直接算 md5 是可行的,我用了一个现成的库(但是好像不能处理中文吧)。这个例子中的 LoginCtrl 大家就不用太关心了,参见官方的文档,走完流程拿到 token 完事。与 ngResource 相关的是 MainCtrl 中的东西。其实从这个例子中就可以看出,目前 ngResource 的机制对于服务端返回的数据的格式是严重依赖的,同时也可以反映出 $http 对一些场景根本无法应对的局限。所以,我现在的想法是理解 ngResource 的思想,真正需要的人自己使用 jQuery 重新实现一遍也许更好。这应该也花不了多少时间, ngResource 的代码本来不多。我为什么说 $http 在一些场景中有局限呢。在这个例子当中,所有的请求都需要带一个签名,签名值是由请求中带的参数根据规则使用 md5 方法计算出的值。我找不到一个 hook 可以让我在请求出去之前修改这个请求(添加上签名)。所以在这个例子当中,我的做法是根据 ngResource 的请求最后会使用 $httpBackend 这个底层服务,在 module 定义时我自己复制官方的相关代码,重新定义 $httpBackend 服务,在需要的地方做我自己的修改:script.src = sign_url(url);不错,我就改了这一句,但我不得不复制了 50 行官方源码到我的例子中。另外一个需要说的是对返回数据的处理。因为 ngResource 会使用返回的数据直接填充实例,所以这个数据格式就很重要。首先,我们可以使用 $http.defaults.transformResponse 来统一处理一下返回的数据,但是这并不能解决所有问题,可目前 ngResource 并不提供对每一个 action 的单独的后处理回调函数项。除非你的服务端是经过专门的适应性设计的,否则你用 ngResource 不可能爽。例子中,我为了获取当前列表的结果,我不得不自己去封装结果:var list_list = List.getList(function(){
var res = list_list[1];
while(list_list.length & 0){list_list.pop()};
angular.forEach(res.list, function(v){
list_list.push(new List({list: v}));
$scope.list_list = list_
$scope.show_add =
});15. AngularJS与其它框架的混用(jQuery, Dojo)这个问题似乎很多人都关心,但是事实是,如果了解了 ng 的工作方式,这本来就不是一个问题了。在我自己使用 ng 的过程当中,一直是混用 jQuery 的,以前还要加上一个 Dojo 。只要了解每种框架的工作方式,在具体的代码中每个框架都做了什么事,那么整体上控制起来就不会有问题。回到 ng 上来看,首先对于 jQuery 来说,最开始说提到过,在 DOM 操作部分, ng 与 jQuery 是兼容的,如果没有 jQuery , ng 自己也实现了兼容的部分 API 。同时,最开始也提到过, ng 的使用最忌讳的一点就是修改 DOM 结构——你应该使用 ng 的模板机制进行数据绑定,以此来控制 DOM 结构,而不是直接操作。换句话来说,在不动 DOM 结构的这个前提之下,你的数据随便怎么改,随便使用哪个框架来控制都是没问题的,到时如有必要使用 $scope.$digest() 来通知 ng 一下即可。下面这个例子,我们使用了 jQuery 中的 Deferred ( $.ajax 就是返回一个 Deferred ),还使用了 ng 的 $timeout ,当然是在 ng 的结构之下:1
&!DOCTYPE html& 2
&html ng-app="Demo"& 3
&meta charset="utf-8" /& 5
&title&AngularJS&/title& 6
&div ng-controller="TestCtrl"&10
&span ng-click="go()"&{{ a }}&/span&11
&script type="text/javascript"14
src="/ajax/libs/jquery/1.9.1/jquery.min.js"&15
&/script&16
&script type="text/javascript"17
src="/ajax/libs/angularjs/1.0.3/angular.min.js"&18
&/script&19
&script type="text/javascript"&21
var app = angular.module('Demo', [], angular.noop);22
app.controller('TestCtrl', function($scope, $timeout){23
$scope.a = '点击我开始';24
var defer = $.Deferred();26
var f = function(){27
if($scope.a == ''){$scope.a = '已停止'; return}28
defer.done(function(){29
$scope.a.length & 10 ? $scope.a += '&' : $scope.a = '&';30
$timeout(f, 100);31
defer.done(function(){$scope.a = '&'; f()});34
$scope.go = function(){36
defer.resolve();37
$timeout(function(){$scope.a = ''}, 5000);38
&/script&41
&/html&再把 Dojo 加进来看与 DOM 结构相关的例子。之前说过,使用 ng 就最好不要手动修改 DOM 结构,但这里说两点:对于整个页面,你可以只在局部使用 ng ,不使用 ng 的地方你可以随意控制 DOM 。如果 DOM 结构有变动,你可以在 DOM 结构定下来之后再初始化 ng 。下面这个例子使用了 AngularJS , jQuery , Dojo :1
&!DOCTYPE html& 2
&meta charset="utf-8" /& 5
&title&AngularJS&/title& 6
&link rel="stylesheet" 7
href="/ajax/libs/dojo/1.9.1/dijit/themes/claro/claro.css" media="screen" /& 8
&body class="claro"&10
&div ng-controller="TestCtrl" id="test_ctrl"&12
&p ng-show="!btn_disable"&14
&button ng-click="change()"&调用dojo修改按钮&/button&15
&p id="btn_wrapper"&18
&button data-dojo-type="dijit/form/Button" type="button"&{{ a }}&/button&19
&input ng-model="dialog_text" ng-init="dialog_text='对话框内容'" /&23
&button ng-click="dialog(dialog_text)"&显示对话框&/button&24
&p ng-show="show_edit_text" style="display:"&27
&span&需要编辑的内容:&/span&28
&input ng-model="text" /&29
&div id="editor_wrapper"&32
&div data-dojo-type="dijit/Editor" id="editor"&&/div&33
&script type="text/javascript"39
src="/ajax/libs/dojo/1.9.1/dojo/dojo.js"&40
&/script&41
&script type="text/javascript"42
src="/ajax/libs/jquery/1.9.1/jquery.min.js"&43
&/script&44
&script type="text/javascript"45
src="/ajax/libs/angularjs/1.0.3/angular.min.js"&46
&/script&47
&script type="text/javascript"&49
require(['dojo/parser', 'dijit/Editor'], function(parser){51
parser.parse($('#editor_wrapper')[0]).then(function(){52
var app = angular.module('Demo', [], angular.noop);53
app.controller('TestCtrl', function($scope, $timeout){55
$scope.a = '我是ng, 也是dojo';56
$scope.show_edit_text =57
$scope.change = function(){59
$scope.a = 'DOM结构已经改变(不建议这样做)';60
require(['dojo/parser', 'dijit/form/Button', 'dojo/domReady!'],61
function(parser){62
parser.parse($('#btn_wrapper')[0]);63
$scope.btn_disable =64
$scope.dialog = function(text){69
require(["dijit/Dialog", "dojo/domReady!"], function(Dialog){70
var dialog = new Dialog({71
title: "对话框哦",72
content: text,73
style: "width: 300px"74
dialog.show();76
require(['dijit/registry'], function(registry){80
var editor = registry.byId('editor');81
$scope.$watch('text', function(new_v){82
editor.setValue(new_v);83
angular.bootstrap(document, ['Demo']);89
&/script&94
&/html&评论评论功能需要javascript的支持
?2010- All rights reserved. Powered by
来自:&&&《》
更多精彩,关注微信号:360doc
馆友评论(0)
您好,请&&或者&&后再进行评论
合作登录:

我要回帖

更多关于 angularjs bootstrap 的文章

 

随机推荐