第二章、数据绑定
2.2 简单的数据绑定
Simple app
Hello {
{ name }}
ng-app 指令定义一个 AngularJS 应用程序。ng-app 声明所有被它包含的元素都属于AngularJS 应用
ng-model 指令把元素值(比如输入域的值)绑定到应用程序。
ng-controller 指令定义了应用程序控制器。DOM元素上的ng-controller声明所有被它包含的元素都属于某个控制器。
AngularJS 表达式写在双大括号内:{ { expression }}。
- 它们可以包含文字、运算符和变量。
- 可以写在 HTML 中
- 支持过滤器,不支持条件判断,循环及异常。
{ { name }} 是通过 ng-model="name" 进行同步。
2.3 数据绑定的最佳实现
通常认为,在视图中通过对象的属性而非对象本身来进行引用绑定,是Angular中的最佳实践。
function MyController($scope) {
$scope.clock = {
now: new Date()
};
var updateClock = function() {
$scope.clock.now = new Date()
};
setInterval(function() {
$scope.$apply(updateClock);
}, 1000);
updateClock();
};
第三章、模块
模块包含了主要的应用代码。一个应用可以包含多个模块,每一个模块都包含了定义具体功能的代码。
AngularJS允许我们使用angular.module()方法来声明模块,这个方法能够接受两个参数,第一个是模块的名称,第二个是依赖列表,也就是可以被注入到模块中的对象列表。angular.module(name,requires);
- name是模块的名称,字符串变量。
- requires包含了一个字符串变量组成的列表,每个元素都是一个模块名称,本模块依赖于这些模块,依赖需要在本模块加载之前由注入器进行预加载。
//是用来定义模块的
angular.module('myApp', []);
// 用于获取应用
angular.module('myApp')
第四章、作用域
4.1 视图和 $scope
AngularJS启动并生成视图时,会将根ng-app元素同$rootScope
进行绑定。$rootScope
是所有$scope
对象的最上层。$rootScope是AngularJS中最接近全局作用域的对象
$scope对象就是一个普通的JavaScript对象,我们可以在其上随意修改或添加属性。
4.2 作用域能做什么
作用域的功能:
- 提供观察者以监视数据模型的变化;
- 可以将数据模型的变化通知给整个应用,甚至是系统外的组件;
- 可以进行嵌套,隔离业务功能和数据;
- 给表达式提供运算时所需的执行环境。
ng-controller和ng-repeat指令会创建自己的子作用域并将它们附加到DOM元素上。
第五章、控制器
控制器并不适合用来执行DOM操作、格式化或数据操作,以及存储数据之外的状态维护操作,允许在$scope
上设置数据
5.1 控制器嵌套
{
{ person }}
点击按钮时,可以在ChildController中访问ParentController中$scope.person
的值
var app=angular.module("myApp",[]);
app.controller("myController",['$scope','aService',...,function($scope,aService,...){
//可以注入你写的factory,provider等等
}]);
controller第一个参数是名称,后面是一个数组,数组的前面是声明注入的内容,可以是n个,最后是个function,function的参数个数也必须是n个,必须跟前面声明注入的内容一一对应,就这样实现了依赖注入
第六章、表达式
- 所有的表达式都在其所属的作用域内部执行,并有访问本地$scope的权限;
- 如果表达式发生了TypeError和ReferenceError并不会抛出异常;
- 不允许使用任何流程控制功能(条件控制,例如if/eles)
- 可以接受过滤器和过滤器链。
6.1 解析angularjs表达式
$watch(watchFn, watchAction, deepWatch)
watchFn该参数是一个带有Angular表达式或者函数的字符串,它会返回被监控的数据模型的当前值
watchAction这是一个函数或者表达式,当watchFn 发生变化时会被调用。
如果是函数的形式,它将会接收到watchFn的新旧两个值,以及作用域对象的引用。function(newValue, oldValue, scope)。
deepWatch如果设置为true,这个可选的布尔型参数将会命令Angular去检查被监控对象的每个属性是否发生了变化。$parse(expression)
将一个AngularJS表达式转换成一个函数function(context,locals)
context[object]:针对你要解析的语句,这个对象中含有你要解析的语句中的表达式(通常是一个scope object)
locals[object]: 关于context中变量的本地变量,对于覆盖context中的变量值很有用。
angular.module("myApp", [])
.controller('MyController',function($scope,$parse) {
$scope.$watch('expr', function(newVal, oldVal, scope) {
if (newVal !== oldVal) {
// 用该表达式设置parseFun
var parseFun = $parse(newVal);
// 获取经过解析后表达式的值
$scope.parsedValue = parseFun(scope);
}
});
});
6.2 插值字符串
要在字符串模板中做插值操作,需要在你的对象中注入$interpolate服务。
$interpolate服务是一个可以接受三个参数的函数,其中第一个参数是必需的。返回一个函数,用来在特定的上下文中运算表达式。
- text(字符串):一个包含字符插值标记的字符串。
- mustHaveExpression(布尔型):如果将这个参数设为true,当传入的字符串中不含有表达式时会返回null。
- trustedContext(字符串):AngularJS会对已经进行过字符插值操作的字符串通过$sec.getTrusted()方法进行严格的上下文转义。
{
{ previewText }}
angular.module('myApp', [])
.controller('MyController', function($scope, $interpolate) {
$scope.$watch('emailBody', function(body) {
if (body) {
var template = $interpolate(body);
$scope.previewText = template({to: $scope.to});
}
};
});
在{ { previewText }}内部的文本中可以将{ { to }}当做一个变量来使用,并对文本的变化进行实时更新。
如果需要在文本中使用不同于{ { }}的符号来标识表达式的开始和结束,可以在$inter polateProvider中配置。
第七章、过滤器
在HTML中的模板绑定符号{ { }}内通过|符号来调用过滤器。
{
{ name | uppercase }}
在JavaScript代码中可以通过$filter
来调用过滤器
app.controller('DemoController', ['$scope', '$filter',
function($scope, $filter) {
$scope.name = $filter('lowercase')('Ari');
}
]);
内置过滤器
- currency
- date
- filter
这个过滤器的第一个参数可以是字符串、对象或是一个用来从数组中选择元素的函数。
我们也可以给filter过滤器传入第二个参数,用来指定预期值同实际值进行比较的方式- 字符串
返回所有包含这个字符串的元素。如果我们想返回不包含该字符串的元素,在参数前加!符号。
{ { ['Ari','Lerner','Likes','To','Eat','Pizza'] | filter:'e' }}
- 对象
AngularJS会将待过滤对象的属性同这个对象中的同名属性进行比较,如果属性值是字符串就会判断是否包含该字符串。
{ { [ {'name': 'Ari','City': 'San Francisco','favorite food': 'Pizza'}, {'name': 'Nate','City': 'San Francisco','favorite food': 'indian food'} ] | filter:{'favorite food': 'Pizza'} }}
- 函数
对每个元素都执行这个函数,返回非假值的元素会出现在新的数组中并返回。
{ { ['Ari','likes','to','travel'] | filter:isCapitalized }} $scope.isCapitalized = function(str) { return str[0] == str[0].toUpperCase(); };
- 字符串
- json
json过滤器可以将一个JSON或JavaScript对象转换成字符串 - limitTo
limitTo过滤器会根据传入的参数生成一个新的数组或字符串,新的数组或字符串的长度取决于传入的参数,通过传入参数的正负值来控制从前面还是从后面开始截取。{ { San Francisco is very cloudy | limitTo:3 }}
- lowercase
- uppercase
- number
number过滤器将数字格式化成文本。它的第二个参数是可选的,用来控制小数点后截取的位数。 - orderBy
orderBy过滤器可以用表达式对指定的数组进行排序。可以接受两个参数,第一个是必需的,第二个是可选的,用来控制排序的方向(是否逆向)。{ { [{ 'name': 'Ari','status': 'awake' },{ 'name': 'Q','status': 'sleeping' },{ 'name': 'Nate','status': 'awake' }] | orderBy:'name':true }}
7.1 自定义过滤器
{
{ 'ginger loves dog treats' | lowercase | capitalize }}
//自定义capitalize过滤器
angular.module('myApp', [])
.filter('capitalize', function() {
return function(input) {
// input是我们传入的字符串
if (input) {
return input[0].toUpperCase() + input.slice(1);
}
});
7.2 表单验证
如果想要屏蔽浏览器对表单的默认验证行为,可以在表单元素上添加novalidate标记。
可以在input元素上使用的所有验证选项
- 最小长度
- 最大长度
- 模式匹配
- 在表单中控制变量
- 未修改的表单
formName.inputFieldName.$pristine
如果未修改,值为true - 修改过的表单
formName.inputFieldName.$dirty
只要用户修改过表单,该值都返回true - 合法的表单
formName.inputFieldName.$valid
- 不合法的表单
formName.inputFieldName.$invalid
- 错误
formName.inputfieldName.$error
如果验证失败,这个属性的值为true - 一些有用的CSS样式 .ng-pristine{} .ng-dirty{} .ng-valid{} .ng-invalid{}
- $parsers
- $formatters
给输入字段添加name属性非常重要:这决定了我们将验证信息展示给用户时如何引用表单输入字段。
- 未修改的表单
第八章、指令简介
8.1 自定义HTML元素和属性
通过AngularJS模块API中的.directive()方法,我们可以通过传入一个字符串和一个函数来注册一个新指令。其中字符串是这个指令的名字函数应该返回
一个对象包含了用来定义和配置指令所需的方法和属性。
angular.module('myApp',[])
.directive('myDirective', function() {
return {
restrict: 'E',
template: '
Click me to go to Google'
};
});
将replace设置为true就将自定义标签从生成的DOM中完全移除掉,并只留下由模版生成的链接
restrict可以指定以元素(E)、属性(A)、类(C)或注释(M)的格式来调用指令,好的经验法则就是始终用属性来声明指
8.2 向指令中传递数据
AngularJS允许通过创建新的子作用域或者隔离作用域来解决这个常见问题
第九章、内置指令
9.1 基础ng属性指令
9.1.1 布尔属性
- ng-disabled 用ng-disabled可以把disabled属性绑定到
表单输入字段上
- ng-readonly 通过ng-readonly可以将某个返回真或假的表达式同是否出现readonly属性进行绑定:
- ng-checked 通过ng-checked将某个表达式同是否出现checked属性进行绑定。
- ng-selected ng-selected可以对是否出现option标签的selected属性进行绑定
9.1.2 类布尔属性
- ng-href 当使用当前作用域中的属性动态创建URL时,应该用ng-href代替href。
- ng-src AngularJS会告诉浏览器在ng-src对应的表达式生效之前不要加载图像
9.2 在指令中使用子作用域
- ng-app
ng-app为AngularJS应用创建$rootScope,任何具有ng-app属性的DOM元素将被标记为$rootScope的起始点。任何嵌套在ng-app内的指令都会继承它 - ng-controller
ng-controller则会以$rootScope或另外一个ng-controller的作用域为原型创建新的子作用域
子$scope只是一个JavaScript对象,其中含有从父级$scope中通过原型继承得到的方法和属性,包括应用的$rootScope - ng-include
使用ng-include可以加载、编译并包含外部HTML片段到当前的应用中。模板的URL被限制在与应用文档相同的域和协议下.Hello { { name }} - ng-switch
这个指令和ng-switch-when及on="propertyName"一起使用,可以在propertyName发生变
化时渲染不同指令到视图中And the winner is
{ { person.name }}
- ng-view
ng-view指令用来设置将被路由管理和放置在HTML中的视图的位置 - ng-if
使用ng-if指令可以完全根据表达式的值在DOM中生成或移除一个元素
ng-if同no-show和ng-hide指令最本质的区别是,它不是通过CSS显示或隐藏DOM节点,而是真正生成或移除节点。 - ng-repeat
ng-repeat用来遍历一个集合或为集合中的每个元素生成一个模板实例- $index:遍历的进度(0...length-1)。
- $first:当元素是遍历的第一个时值为true。
- $middle:当元素处于第一个和最后元素之间时值为true。
- $last:当元素是遍历的最后一个时值为true。
- $even:当
$index
值是偶数时值为true。 - $odd:当
$index
值是奇数时值为true。
- ng-init
ng-init指令用来在指令被调用时设置内部作用域的初始状态。 - { { }} 与ng-bind
{ { }}语法是AngularJS内置的模板语法,它会在内部$scope和视图之间创建绑定.在屏幕可视的区域内使用{ { }}会导致页面加载时未渲染的元素发生闪烁,用ng-bind可以避免这个问题。 ng-cloak
除使用ng-bind来避免未渲染元素闪烁,还可以在含有{ { }}的元素上使用ng-cloak指令,ng-cloak指令会将内部元素隐藏,直到路由调用对应的页面时才显示出来{ { greeting }}
- ng-bind-template
同ng-bind指令类似,ng-bind-template用来在视图中绑定多个表达式 - ng-model
ng-model指令用来将input、select、text area或自定义表单控件同包含它们的作用域中的属性进行绑定
我们应该始终用ngModel来绑定$scope上一个数据模型内的属性,而不是$scope上的属性,这可以避免在作用域或后代作用域中发生属性覆盖。 - ng-show/ng-hide
ng-show和ng-hide根据所给表达式的值来显示或隐藏HTML元素
元素的显示或隐藏是通过移除或添加ng-hide这个CSS类来实现的。.ng-hide类被预先定义并且它的display属性的值为none - ng-change
这个指令会在表单输入发生变化时计算给定表达式的值。因为要处理表单输入,这个指令要和ngModel联合起来使用。 - ng-form
ng-form用来在一个表单内部嵌套另一个表单。普通的HTML标签不允许嵌套,但ng-form可以。
- ng-click
ng-click用来指定一个元素被点击时调用的方法或表达式 ng-select
ng-select用来将数据同HTML的元素进行绑定。这个指令可以和ng-model以及ng-options指令一同使用
Best City: { { city.name }}angular.module('myApp',[]) .controller('CityController',function($scope) { $scope.cities = [ {name: 'Seattle'}, {name: 'San Francisco'}, {name: 'Chicago'}, {name: 'New York'}, {name: 'Boston'} ]; });- ng-submit
ng-submit用来将表达式同onsubmit事件进行绑定。这个指令同时会阻止默认行为(发送请求并重新加载页面),除非表单不含有action属性 - ng-class
使用ng-class 动态设置元素的类,方法是绑定一个代表所有需要添加的类的表达式。 - ng-attr-(suffix)
指出我们有一个非法属性。可以用ng-attr-cx来解决这个问题。
第十章、指令详解
10.1 指令定义
directive()这个方法是用来定义指令的
angular.module('myApp', [])
.directive(name,factory_function(){
// 指令定义放在这里
});
angular.module('myApp', [])
.directive('myDirective', function() {
return {
restrict: String,
priority: Number,
terminal: Boolean,
template: String or Template Function:
function(tElement, tAttrs) (...},
templateUrl: String,
replace: Boolean or String,
scope: Boolean or Object,
transclude: Boolean,
controller: String or function(scope, element, attrs, transclude, otherInjectables){ ... },
controllerAs: String,
require: String,
link: function(scope, iElement, iAttrs) { ... },
compile:
// 返回一个对象或连接函数,如下所示:
function(tElement, tAttrs, transclude) {
return {
pre: function(scope, iElement, iAttrs, controller) { ... },
post: function(scope, iElement, iAttrs, controller) { ... }
}
// 或者
return function postLink(...) { ... }
}
};
});
指令的生命周期开始于$compile方法并结束于link方法
10.1.1 restrict(字符串)
restrict是一个可选的参数。它告诉AngularJS这个指令在DOM中可以何种形式被声明,默认AngularJS认为restrict的值是A,即以属性的形式来进行声明
10.1.2 优先级(数值型)
如果一个元素上具有两个优先级相同的指令,声明在前面的那个会被优先调用。如果其中一个的优先级更高,则不管声明的顺序如何都会被优先调用:具有更高优先级的指令总是优先运行
10.1.3 terminal(布尔型)
这个参数用来告诉AngularJS停止运行当前元素上比本指令优先级低的指令。
10.1.4 template(字符串或函数)
template参数是可选的,必须被设置为以下两种形式之一:
- 一段HTML文本;
- 一个可以接受两个参数的函数,参数为tElement和tAttrs,并返回一个代表模板的字符串
在实际生产中,更好的选择是使用templateUrl参数引用外部模板
10.1.5 templateUrl(字符串或函数)
templateUrl是可选的参数,可以是以下类型:
- 一个代表外部HTML文件路径的字符串;
- 一个可以接受两个参数的函数,参数为tElement和tAttrs,并返回一个外部HTML文件路径的字符串。
默认情况下,调用指令时会在后台通过Ajax来请求HTML模板文件,模板加载后,AngularJS会将它默认缓存到$templateCache服务中。在实际生产中,可以提前将模板缓存到一个定义模板的JavaScript文件中,这样就不需要通过XHR来加载模板了
10.1.6 replace(布尔型)
replace是一个可选参数,如果设置了这个参数,值必须为true,因为默认值为false。默认值意味着模板会被当作子元素插入到调用此指令的元素内部
10.2 指令作用域
10.2.1 scope参数(布尔型或对象)
scope参数是可选的,可以被设置为true或一个对象。默认值是false。
当scope设置为true时,会从父作用域继承并创建一个新的作用域对象。
内置指令ng-controller的作用,就是从父级作用域继承并创建一个新的子作用域。
如果要创建一个能够从外部原型继承作用域的指令,需将scope属性设置为true
10.2.2 隔离作用域
具有隔离作用域的指令最主要的使用场景是创建可复用的组件
10.3 绑定策略
AngularJS提供了几种方法能够将指令内部的隔离作用域,同指令外部的作用域进行数据绑定。
为了让新的指令作用域可以访问当前本地作用域中的变量,需要使用下面三种别名中的一种
- 本地作用域属性:使用@符号将本地作用域同DOM属性的值进行绑定。指令内部作用域可以使用外部作用域的变量
- 双向绑定:通过=可以将本地作用域上的属性同父级作用域上的属性进行双向的数据绑定。
- 父级作用域绑定 通过&符号可以对父级作用域进行绑定,以便在其中运行函数。意味着对这个值进行设置时会生成一个指向父级作用域的包装函数。
10.3.1 transclude
transclude是一个可选的参数。如果设置了,其值必须为true,它的默认值是false。
嵌入通常用来创建可复用的组件,典型的例子是模态对话框或导航栏。
为了将作用域传递进去,scope参数的值必须通过{}或true设置成隔离作用域。如果没有设置scope参数,那么指令内部的作用域将被设置为传入模板的作用域
如果指令使用了transclude参数,那么在控制器(下面马上会介绍)中就无法正常监听数据模型的变化了。这就是最佳实践总是建议在链接函数里使用$watch
服务的原因。
10.3.2 controller(字符串或函数)
controller参数可以是一个字符串或一个函数
angular.module('myApp', [])
.directive('myDirective', function() {
restrict: 'A', // 始终需要
controller: 'SomeController'
})
可以在指令内部通过匿名构造函数的方式来定义一个内联的控制器:
angular.module('myApp',[])
.directive('myDirective', function() {
restrict: 'A',
controller:
function($scope, $element, $attrs, $transclude) {
// 控制器逻辑放在这里
}
});
控制器中也有一些特殊的服务可以被注入到指令当中。这些服务有:
- $scope 与指令元素相关联的当前作用域
- $element 当前指令对应的元素
- $attrs 由当前元素的属性组成的对象
- $transclude 嵌入链接函数会与对应的嵌入作用域进行预绑定