Angularjs 学习笔记

 

Angular    

简介

 

js 是基础,angularJs 是 js 框架

 

起源

  • 2009Google Feedback Project
  • 6个月开发的17000行前端代码,使用3周压缩到1500

 

简介

  • Angularjs 致力于减轻开发人员在开发AJAX应用过程中的痛苦
  • 官网:http://www.angularjs.org/

 

ajax 开发是单页应用

概念

  • 客户端模版
  • MVC
  • 数据绑定
  • 依赖注入

 

客户端模版

  • Angular中,模版和数据都会被发送到浏览器中,然后在客户端进行装配

【以前模板和数据是在后端装配完的,如servlet】

 

MVC

  • MVC核心概念:把管理数据的代码(model)、应用逻辑代码(controller)、向用户展示数据的代码(view)清晰地分离开
  • Angularjs应用中:
    视图就是Document Object Model
    控制器就是Javascript
    模型数据则被存储在对象的属性中

 

数据绑定

  • 数据绑定可自动将modelview间的数据同步。
  • Angular实现数据绑定的方式,可以让我们把model当作程序中唯一可信的数据来源。view始终是model的投影。当model发生变化时,会自动反映到view上。

 

经典模板系统中的数据绑定

 

  • 大多数模板系统中的数据绑定都是单向的
  • 把模板与model合并在一起变成view,如果在合并之后,model发生了变化,不会自动反映到view上。
  • 用户在view上的交互也不会反映到model中,开发者必须写大量代码不断地在viewmodel之间同步数据。

 

Anguarjs 模板中的数据绑定

 

  • 模板是在浏览器中编译的,在编译阶段产生了一个实时更新(live)的视图
  • 不论在model或是view上发生了变化,都会立刻反映到对方。
  • model成为程序中唯一真实的数据来源,极大地简化了开发者需要处理的编程模型。

依赖注入

依赖注入是一种软件设计模式,用来处理代码的依赖关系。【如java spring Ioc】

 

  • Angular的依赖注入只是简单的获取它所需要的东西,而不需要创建那些他们所依赖的东西

Demo 001-依赖注入

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>Angularjs-视频教程-001-简介</title>
  5. </head>
  6. <body>
  7. <script>
  8. var A = function () {
  9. this.getName = function () {
  10. return '张三';
  11. }
  12. }
  13. var a = new A;
  14. var B = function () {
  15. // B 依赖于 a,b对象中需要用到a对象
  16. document.write(a.getName());
  17. }
  18. // a 注入 b,将a传入b对象中
  19. var b = new B();
  20. //在用b对象时需要用到a对象 ,js里2个方法实现:
  21. // 1. 将a 传入到b里面去
  22. // 2. a是全局变量
  23. </script>
  24. </body>
  25. </html>

指令

ng-app

  • ng-app指令告诉Angular应该管理页面中的哪一块

 

【写在body里面,管理整个body里面的元素,管理整个页面】

 

模版显示文本 && ng-bind

  • {{expression}}【写在双大括号里面的是表达式】
  • <tag ng-bind="expression"></tag>

 

 

Demo 002--数据双向绑定:

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

</head>

<body ng-app>

<!--

view => 12131

model => 12131

3 view

数据是双向绑定的

-->

<input type="text" ng-model="name" value=""/>

<!--angular的表达式-->

{{ name }}

<input type="text" ng-model="name" value=""/>

<script type="text/javascript" src="../vendor/angular/angularjs.js"></script>

</body>

</html>

 

 

javascript 表达式

创建一个字符串,使用函数eval解析

  • var str = 'alert(1+2)';
  • eval(str)

 

 

angular 表达式

  • angular 表达式 通过$parse服务解析执行。
  • Javascript 表达式的区别:
    1.
    属性求值:所有属性的求值是对于scope的,而javascript是对于window对象的。

【var a=3,是针对window的属性】

2.宽容:表达式求值,对于undefinednullangular是宽容的,但Javascript会产生NullPointerExceptions

3.没有流程控制语句:在angular表达式里,不能做以下任何的事:条件分支、循环、抛出异常

4.过滤器(filters):我们可以就将表达式的结果传入过滤器链(filter chains

 

 

ng-controller

  • 控制器就是你所编写的类或者类型,它的作用是告诉Angular该模型是由哪些对象或者基本数据结构构成的

 

Demo 003--控制器

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

</head>

<body>

<div ng-app="">

<div ng-controller="firstController">

<input type="text" value="" ng-model="name"/>

<input type="text" value="" ng-model="age"/>

{{name}}

{{age}}

</div>

</div>

<script type="text/javascript" src="app/index.js"></script>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

</body>

</html>

 

 

var firstController = function($scope){

//$scope 我们叫做作用域,是管理firstController控制器范围所有的数据的作用域,和js函数的作用域一样

// 申明一个默认的Model

$scope.name = '张三';

$scope.age = 20;

}

 

 

 

Demo 005-多个控制器 作用域链的问题

AngularJs 多个controller作用域和 js 函数变量左右域的原理类似, 函数里面使用变量的时候,优先找函数作用域里面的是否有该变量,如果没有,就去访问函数外面的变量.

 

下面的demo中,总共有三个作用域,一个是ng-app, 另外两个分别是firstController、secondController

 

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

</head>

<body>

<div ng-app="">

<div ng-controller="firstController">

<input type="text" value="" ng-model="name"/>

<div ng-controller="secondController">

<input type="text" value="" ng-model="name"/>

</div>

</div>

</div>

<script>

function first(){

var name = '张三';

function second(){

var name = '张三12121212121';

alert(name);

}

}

</script>

<script type="text/javascript" src="app/index.js"></script>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

</body>

</html>

 

Index.js

 

var firstController = function($scope){

$scope.name = '张三';

console.log($scope);

}

var secondController = function($scope){

console.log($scope);

}

 

 

ng-bind

ng-bind 也可以展现$scope里面的数据,比{{}} 展示数据的优势在于,使用ng-bind,当angularJs 没有加载完的时候,不会显示任何东西,而使用{{}},会显示乱码

 

$scope

 

什么是 scope

  • scope是一个指向应用modelobject,也是表达式的执行上下文。
  • scope被放置于一个类似应用的DOM结构的层次结构中。
  • scope 类似js 的作用域链

 

 

scope的特性

  • scope提供$watch API,用于监测model的变化。
  • scope提供$apply,在"Angular realm"controllerserverangular event handler)之外,从系统到视图传播任何model的变化。
  • scope可以在提供到被共享的model属性的访问的时候,被嵌入到独立的应用组件中。scope通过(原型),从parent scope中继承属性。

 

 

$apply

【$apply方法有什么用?当apply 方法执行完之后,会触发angular里面的脏检查,检查每一个scope里面的属性是否有变化,如果有变化,所对应的其他的model 、value 都会变化】

  • $scope.$apply(expression)
  • $apply()方法可以在angular框架之外执行angular JS的表达式,例如:DOM事件、setTimeoutXHR或其他第三方的库

 

 

angular是怎么知道变量发生了改变

  • 要知道一个变量变了,方法不外乎两种
  • 1.能通过固定的接口才能改变变量的值,比如说只能通过 set() 设置变量的值,set被调用时比较一下就知道了。这中方法的缺点洗是写法繁琐
  • 2.脏检查,将原对象复制一份快照,在某个时间,比较现在对象与快照的值,如果不一样就表明发生变化,这个策略要保留两份变量,而且要遍历对象,比较每个属性,这样会有一定性能问题

 

 

angular的策略

  • angular的实现是使用脏检查
  • angular的策略
    1.
    不会脏检查所有的对象,当对象被绑定到html中,这个对象添加为检查对象(watcher)。
    2.
    不会脏检查所有的属性,同样当属性被绑定后,这个属性会被列为检查的属性。
  • angular程序初始化时,会将绑定的对象的属性添加为监听对象(watcher),也就是说一个对象绑定了N个属性,就会添加Nwatcher

 

 

什么时候去脏检查

  • angular 所系统的方法中都会触发比较事件,比如:controller 初始化的时候,所有以ng-开头的事件执行后,都会触发脏检查

 

 

手动触发脏检查

  • $apply仅仅只是进入angular context ,然后通过$digest去触发脏检查
  • $apply如果不给参数的话,会检查该$scope里的所有监听的属性,推荐给上参数

 

【只有需要手动触发的时候脏检查,才需要调用apply方法。否则,比如,:controller 初始化的时候,系统会自动在后台调用apply方法。】

 

Demo 006-$scope里$apply、$digest方法

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

</head>

<body>

<div ng-app="">

<div ng-controller="firstController">

{{date}}

</div>

</div>

<script type="text/javascript" src="app/index.js"></script>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

</body>

</html>

 

Index.js

var firstController = function($scope){

$scope.date = new Date();

// setInterval(function(){

// // 这里虽然变 但是并没有触发 脏检查

// $scope.date = new Date();

// },1000)

setInterval(function(){

$scope.$apply(function(){

$scope.date = new Date(); //....会去触发脏检查

})

},1000) // 触发一次脏检查

}

 

 

$digest()

  • 所属的scope和其所有子scope的脏检查,脏检查又会触发$watch(),整个Angular双向绑定机制就活了起来~
  • 查看$apply方法源代码可以知道,不建议直接调用$digest(),而应该使用$apply()$apply其实不能把信直接送给$digest,之间还有$eval门卫把关,如果$apply带的表达式不合法,$eval会把错误送交$exceptionHandler,合法才触发digest,所以更安全

 

 

$watch

  • digest执行时,如果watch观察的value与上次执行时不一样时,就会被触发
  • AngularJS内部的watch实现了页面随model的及时更新

    函数

  • $watch(watchFn,watchAction,deepWatch)

    参数:
    watchFn: angular
    表达式或函数的字符串【表达式是有上下文关系的】
    watchAction(newValue,oldValue,scope): watchFn
    发生变化会被调用
    deepWacth:
    可选的,布尔值命令检查被监控的对象的每个属性是否发生变化

     

  • $watch会返回一个函数,想要注销这个watch可以使用函数

Demo 007-$scope里的$watch方法

应用场景,可以是购物车 当你购买到一定数量的商品的时候,折扣发生变化。

 

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

</head>

<body>

<div ng-app="">

<div ng-controller="firstController">

<input type="text" value="" ng-model="name"/>

改变次数:{{count}}-{{name}}

</div>

</div>

<script type="text/javascript" src="app/index.js"></script>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

</body>

</html>

 

var firstController = function($scope){

$scope.name = '张三';

$scope.data = {

name :'李四',

count:20

}

$scope.count = 0;

// 监听一个model【变量】, 当一个model每次改变时 都会触发第2个函数

$scope.$watch('name',function(newValue,oldValue){

++$scope.count;

if($scope.count > 30){

$scope.name = '已经大于30次了';

}

});

//监听的是data是一个对象,如果要监听date中的nameage变化,那么第三个参数必须设置为true才行

$scope.$watch('data',function(){},true)

}

 

 

ng-repeat 指令 重复 HTML 元素

ng-repeat 指令用在一个对象数组上:

 

<div ng-app="" ng-init="names=[

{name:'Jani',country:'Norway'},

{name:'Hege',country:'Sweden'},

{name:'Kai',country:'Denmark'}]">

<p>循环对象:</p>

<ul>

<li ng-repeat="x in names">

{{ x.name + ', ' + x.country }}

</li>

</ul>

</div>

 

 

ng-repeat指令会重复一个 HTML 元素:

<div ng-app="" ng-init="names=['Jani','Hege','Kai']">

<p>使用 ng-repeat 来循环数组</p>

<ul>

<li ng-repeat="x in names">

{{ x }}

</li>

</ul>

</div>

 

 

Demo 综合练习 008~011-练习 购物车

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<link rel="stylesheet" href="../../vendor/bootstrap3/css/bootstrap.min.css"/>

</head>

<body ng-app>

<div ng-controller="cartController" class="container">

<table class="table" ng-show="cart.length">

<thead>

<tr>

<th>产品编号</th>

<th>产品名字</th>

<th>购买数量</th>

<th>产品单价</th>

<th>产品总价</th>

<th>操作</th>

</tr>

</thead>

<tbody>

<tr ng-repeat="item in cart">

<td>{{item.id}}</td>

<td>{{item.name}}</td>

<td>

<button type="button" ng-click="reduce(item.id)" class="btn tn-primary">-</button>

<input type="text" value="{{item.quantity}}" ng-model="item.quantity" >

<button type="button" ng-click="add(item.id)" class="btn tn-primary">+</button>

</td>

<td>{{item.price}}</td>

<td>{{item.price * item.quantity}}</td>

<td>

<button type="button" ng-click="remove(item.id)" class="btn btn-danger">移除</button>

</td>

</tr>

<tr>

<td>

总购买价

</td>

<td>

{{totalPrice()}}

</td>

<td>

总购买数量

</td>

<td>

{{totalQuantity()}}

</td>

<td colspan="2">

<button type="button" ng-click="cart = {}" class="btn btn-danger">清空购物车</button>

</td>

</tr>

</tbody>

</table>

<p ng-show="!cart.length">您的购物车为空</p>

</div>

<script type="text/javascript" src="app/index.js"></script>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

</body>

</html>

 

Js文件

 

var cartController = function ($scope) {

$scope.cart = [

{

id: 1000,

name: 'iphone5s',

quantity: 3,

price: 4300

},

{

id: 3300,

name: 'iphone5',

quantity: 30,

price: 3300

},

{

id: 232,

name: 'imac',

quantity: 4,

price: 23000

},

{

id: 1400,

name: 'ipad',

quantity: 5,

price: 6900

}

];

/**

* 计算购物总价

*/

$scope.totalPrice = function () {

var total = 0;

angular.forEach($scope.cart, function (item) {

total += item.quantity * item.price;

})

return total;

}

/**

* 计算总购买数

*/

$scope.totalQuantity = function () {

var total = 0;

angular.forEach($scope.cart, function (item) {

total += parseInt(item.quantity);

})

return total;

}

/**

* 找一个元素的索引

*/

var findIndex = function (id) {

var index = -1;

angular.forEach($scope.cart, function (item, key) {

if (item.id === id) {

index = key;

return;

}

});

return index;

}

/**

* 为某个产品添加一个数量

*/

$scope.add = function (id) {

var index = findIndex(id);

 

if (index !== -1) {

++$scope.cart[index].quantity;

}

}

/**

* 为某个产品减少一个数量

*/

$scope.reduce = function (id) {

var index = findIndex(id);

if (index !== -1) {

var item = $scope.cart[index];

if(item.quantity > 1){

--item.quantity;

}else{

var returnKey = confirm('是否从购物车内删除该产品!');

if(returnKey){

$scope.remove(id);

}

}

}

}

/**

* 移除一项

*/

$scope.remove = function (id) {

var index = findIndex(id);

// 如果找到了那个item

if (index !== -1) {

$scope.cart.splice(index, 1);

}

//ng-click ,ng开头的,调用之后,会自动做脏检查。会更新所有的参数、表达式值,这就是双向绑定的好处。

}

// 监听数量 如果小于 1 则让用户判断是否要删除产品    

$scope.$watch('cart',function(newValue,oldValue){

angular.forEach(newValue,function(item,key){

if(item.quantity < 1){

var returnKey = confirm('是否从购物车内删除该产品!');

if(returnKey){

$scope.remove(item.id);

}else{

item.quantity = oldValue[key].quantity;

}

}

})

},true);

}

 

 

 

 

scope生命周期

  • 1.用户请求应用起始页
  • 2.angular 被加载,查找ng-app指令
  • 3.Angular 遍历模版,查找指令
  • 4.controller被启用,$scope被注入进来
  • 5.在模版link过程中,指令在scope中注册$watch。这些watch将会被用作向DOM传播model的值。
  • 5.当在controller中做同步的工作时angular API 已经隐式地做了$apply操作
  • 6.$apply的结尾,angular会在root scope执行一个$digest周期,这将会传播到所有child scope中。在$digest周期中,所有注册了$watch的表达式或者function都会被检查,判断model是否发生了改变,如果改变发生了,那么对应的$watch监听器将会被调用。
  • 7.child scope不再是必须的时候,child scope的产生者有责任通过scope.$destroy() API销毁它们(child scope)。这将会停止$digest的调用传播传播到child scope中,让被child scope model使用的内存可以被gc回收。

 

 

$eval && $evalAsync

  • 在作用域的上下文中执行表达式
  • $eval(expression)
  • $evalAsync接受一个函数,把它列入计划,在当前正持续的digest中或者下一次digest之前执行,即使它已经被延迟了,仍然会在现有的digest遍历中被执行,类似于settimeout(fun,0)

 

 

$broadcast && $emit && $on

  • $broadcast:会把事件广播给所有子controller
  • $emit:则会将事件冒泡传递给父controller
  • $on:angular的事件注册函数
  • 可以简单实现解决angular controller之间的通信
  • 事件也会产生一个event对象,类似与dom中的事件冒泡等机制

 

 

$new && $destroy

  • $new 创建一个新的作用域
  • $destory 销毁一个作用域
  • 作用域的继承是类似于javascript的原型继承,会有类似的原型链

 

 

Module 模块 (视频12)

 

AngularJS中的Module类负责定义应用如何启动,它还可以通过声明的方式定义应用中的各个片段。我们来看看它是如何实现这些功能的。

.Main方法在哪里

如果你是从Java或者Python编程语言转过来的,那么你可能很想知道AngularJS里面的main方法在哪里?这个把所有东西启动起来,并且第一个被执行的方法在哪里?JavaScript代码里面负责实例化并且把所有东西组合到一起,然后命令应用开始运行的那个方法在哪里?

事实上,AngularJS并没有main方法,AngularJS使用模块的概念来代替main方法。模块允许我们通过声明的方式来描述应用中的依赖关系,以及如何进行组装和启动。使用这种方式的原因如下:

1.模块是声明式的。这就意味着它编写起来更加容易,同时理解起来也很容易,阅读它就像读普通的英文一样!

2.它是模块化的。这就迫使你去思考如何定义你的组件和依赖关系,让它们变得更加清晰。

3.它让测试更加容易。在单元测试中,你可以有选择地加入模块,并且可以避免代码中存在无法进行单元测试的内容。同时,在场景测试中,你可以加载其他额外的模块,这样就可以更好地和其他组件配合使用。

例如,在我们的应用中有一个叫做"MyAwesomeApp"的模块。在HTML里面,只要把以下内容添加到<html>标签中(或者从技术上说,可以添加到任何标签中):

<html ng-app="MyAwesomeApp">

ng-app指令就会告诉AngularJS使用MyAwesomeApp模块来启动你的应用。那么,应该如何定义模块呢?举例来说,我们建议你为服务、指令和过滤器分别定义不同的模块。然后你的主模块可以声明依赖这些模块。

这样可以使得模块管理更加容易,因为它们都是良好的、完备的代码块,每个模块有且只有一种职能。同时,单元测试可以只加载它们所关注的模块,这样就可以减少初始化的次数,单元测试也会变得更精致、更专注。

.加载和依赖

模块加载动作发生在两个不同的阶段,这一点从函数名上面就可以反映出来,它们分别是Config代码块和Run代码块(或者叫做阶段)。

1.Config代码块

在这一阶段里面,AngularJS会连接并注册好所有数据源。因此,只有数据源和常量可以注入到Config代码块中。那些不确定是否已经初始化好的服务不能注入进来。

2.Run代码块

Run代码块用来启动你的应用,并且在注射器创建完成之后开始执行。为了避免在这一点开始之后再对系统进行配置操作,只有实例和常量可以被注入到Run代码块中。你会发现,在AngularJS中,Run代码块是与main方法最类似的东西。

.快捷方法

利用模块可以做什么呢?我们可以用它来实例化控制器、指令、过滤器以及服务,但是利用模块类还可以做更多事情。如下模块配置的API方法:

1.config(configFn)

利用此方法可以做一些注册工作,这些工作需要在模块加载时完成。

http://www.cnblogs.com/sean-/p/4952183.html

 

 

 

什么是Module

  • 大部分应用都有一个主方法(main)用来实例化、组织、启动应用。
  • AngularJS应用没有主方法,而是使用模块来声明应用应该如何启动。
  • 模块允许通过声明的方式来描述应用中的依赖关系,以及如何进行组装和启动

 

 

Angular 模块

 

  • 模块是组织业务的一个框框,在一个模块当中定义多个服务。当引入了一个模块的时候,就可以使用这个模块提供的一种或多种服务了。
  • AngularJS 本身的一个默认模块叫做 ng ,它提供了 $http $scope等等服务

     

  • 服务只是模块提供的多种机制中的一种,其它的还有指令( directive ),过滤器( filter ),及其它配置信息。

     

  • 也可以在已有的模块中新定义一个服务,也可以先新定义一个模块,然后在新模块中定义新服务。
  • 服务是需要显式地的声明依赖(引入)关系的,让 ng 自动地做注入

 

 

Module优点

 

  • 启动过程是声明式的,更容易懂。
  • 在单元测试是不需要加载全部模块的,因此这种方式有助于写单元测试。
  • 可以在特定情况的测试中增加额外的模块,这些模块能更改配置,能帮助进行端对端的测试。
  • 第三方代码可以作为可复用的module打包到angular
  • 模块可以以任何先后或者并行的顺序加载(因为模块的执行本身是延迟的)。

 

 

ng-app

  • 通过ng-app指定对应的模块应用启动

 

 

定义模块

  • angular.module(name, [requires], configFn);

    参数:

  • name:定义的模块名
  • requires:该模块所依赖的模块,如果,没有依赖的模块填[]
  • configFn 会在模块初始化时执行,可以在里配置模块的服务
  • configFn @see angular.config()

 

Demo 012-模块和控制器

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

</head>

<body>

<!--这块区域由myApp 模块来管理-->

<!--一个页面中不能有多个ng-app ,模块也不能嵌套-->

<div ng-app="myApp">

<div ng-controller="firstController">

{{name}}

</div>

</div>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

<!--index.js文件不能放在angularjs.js 文件之前,否则读取 index.js文件的内容的时候,还没有读取angularjs.js,而报错-->

<script type="text/javascript" src="app/index.js"></script>

</body>

</html>

 

 

//模块创建完之后,返回模块对象,赋值给myApp

var myApp = angular.module('myApp',[]);

//这样写表示,firstController控制器是属于,myApp模块的

myApp.controller('firstController',function($scope){

$scope.name = '张三';

});

 

 

 

定义服务 $provider

  • 服务本身是一个任意的对象。
  • ng 提供服务的过程涉及它的依赖注入机制。
  • angular 是用$provider对象来实现自动依赖注入机制,注入机制通过调用一个 provider $get() 方法,把得到的对象作为参数进行相关调用
  • $provider.provider 是一种定义服务的方法 , $provider还提供了很多很简便的方法,这些简便的方法还直接被module所引用

 

Demo 013-$provide里provider方法

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

</head>

<body>

<div ng-app="myApp">

<div ng-controller="firstController">

{{name}}

</div>

</div>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

<script type="text/javascript" src="app/index.js"></script>

</body>

</html>

 

 

//因模块先于controller执行,故在模块启动的时候,我们可以在模块中配置一些相关的信息,给controller使用

var myApp = angular.module('myApp',[],function($provide){

//自定义服务,模块myApp定义好服务CustomService之后,在模块的任意的controller中都可以调用该服务。

$provide.provider('CustomService',function(){//服务名:CustomService

this.$get = function(){

return {

message : 'CustomService Message'

}

}

});

$provide.provider('CustomService2',function(){

this.$get = function(){

return {

message : 'CustomService2 Message'

}

}

});

});

myApp.controller('firstController',function(CustomService,$scope,CustomService2){//参数的顺序遂意

$scope.name = '张三';

console.log(CustomService2);

});

 

 

 

 

$provider.factory

  • factory 方法直接把一个函数当成是一个对象的 $get() 方法
  • @see module.factory
  • 返回的内容可以是任何类型

 

 

$provider.service

  • factory类似,但返回的东西必须是对象
  • @see module.service

     

Demo 014-$provide里factory、service方法

 

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

</head>

<body>

<div ng-app="myApp">

<div ng-controller="firstController">

{{name}}

</div>

</div>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

<script type="text/javascript" src="app/index.js"></script>

</body>

</html>

 

 

var myApp = angular.module('myApp',[],function($provide){

// 自定义服务

$provide.provider('CustomService',function(){

this.$get = function(){

return {

message : 'CustomService Message'

}

}

});

// 自定义工厂,返回的内容可以是任何类型

$provide.factory('CustomFactory',function(){

return [1,2,3,4,5,6,7];

});

// 自定义服务

$provide.service('CustomService2',function(){

return 'aaa';//l factory类似,但返回的东西必须是对象,不能事字符串、数字等基本类型。数组是引用类型

})

});

myApp.controller('firstController',function($scope,CustomFactory,CustomService2){

$scope.name = '张三';

console.log(CustomFactory);

console.log(CustomService2);

});

 

 

Demo 015-多个控制器内共享数据

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

</head>

<body>

<div ng-app="myApp">

<!--两个Controller不存在包含关系,存在两个$scope -->

<div ng-controller="firstController">

first.data <input type="text" ng-model="data.name" />

first.Data <input type="text" ng-model="Data.message" />

<p>

first-name:{{data.name}}

</p>

<p>

first-message:{{Data.message}}

</p>

</div>

<div ng-controller="secondController">

<p>

second-name:{{data.name}}

</p>

<p>

second-message:{{Data.message}}

</p>

</div>

</div>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

<script type="text/javascript" src="app/index.js"></script>

</body>

</html>

 

 

 

angular.module('myApp',[])

.factory('Data',function(){ // this.$get = function(){}

return {

message : '共享的数据'

};

})

.controller('firstController',function($scope,Data){

$scope.data = {//对象,引用类型,一个地方变了,全部都变了

name : '张三'

};

$scope.Data = Data;

})

.controller('secondController',function($scope,Data){

$scope.data = $scope.$$prevSibling.data;//prevSibling上一个sope域中的数据

$scope.Data = Data;

});

 

 

 

显式和隐式依赖注入

  • service当作被依赖的资源加载到controller中的方法,与加载到其他服务中的方法很相似。
  • javascript是一个动态语言,DI不能弄明白应该通过参数类型注入哪一个service
  • 显式依赖:要通过$inject属性指定service名称, 它是一个包含需要注入的service名称的字符串数组,工厂方法中的参数顺序,与service 在数组中的顺序一致。
  • 隐式依赖:则允许通过参数名称决定依赖,$scope

 

 

Filters

 

什么是angular 过滤器

  • 是用于对数据的格式化,或者筛选的函数,可以直接在模板中通过一种语法使用
  • {{ expression | filter }}
  • {{ expression | filter1 | filter2 }}
  • {{ expression | filter1:param,.}}【参数使用冒号分割】

 

 

过滤器种类

  • Number:数字格式化
  • currency:货币格式化
  • date 日期格式化
  • limitTo 截取数据
  • lowercase
  • uppercase
  • filter
  • json
  • orderBy

 

 

017-过滤器 limitTo、lowercase、uppercase 、filter 、orderBy、json

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

</head>

<body>

<div ng-app="myApp">

<div ng-controller="firstController">

<!--[1,2,3,4,5] 显示前5-->

<p>{{[1,2,3,4,5,6,7] | limitTo:5}}</p>

<!--[3,4,5,6,7],显示最后五位-->

<p>{{[1,2,3,4,5,6,7] | limitTo:-5}}</p>

<!-- hello world -->

<p>{{data.message | lowercase}}</p>

<!-- HELLO WORLD -->

<p>{{data.message | uppercase}}</p>

<p>

<!-- [{"name":"上海11212","py":"shanghai"}],【过滤包含:上海的项】-->

{{ data.city | filter : '上海'}}

</p>

<p>

<!-- [],【只匹配value值】-->

{{ data.city | filter : 'name'}}

</p>

 

<p>

<!-- name":"上海11212","py":"shanghai"},{"name":"北京","py":"beijing"},【拼音里面是否有g-->

{{ data.city | filter : {py:'g'} }}

</p>

 

<p>

<!-- [{"name":"上海11212","py":"shanghai"},{"name":"四川","py":"sichuan"}]-->

{{ data.city | filter : checkName }}

</p>

 

<p>

<!-- [{"name":"北京","py":"beijing"},{"name":"上海11212","py":"shanghai"},{"name":"四川","py":"sichuan"}] -->

<!-- 默认顺序是 正序 asc a~z 【按照拼音排序】 -->

{{ data.city | orderBy : 'py'}}

 

<!-- 默认顺序是 反序 desc z~a -->

<!-- [{"name":"四川","py":"sichuan"},{"name":"上海11212","py":"shanghai"},{"name":"北京","py":"beijing"}] -->

{{ data.city | orderBy : '-py'}}

</p>

</div>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

<script type="text/javascript" src="app/index.js"></script>

</body>

</html>

 

 

angular.module('myApp',[])

.factory('Data',function(){

return {

message : 'Hello World',

city : [

{

name:'上海11212',

py : 'shanghai'

},

{

name:'北京',

py : 'beijing'

},

{

name:'四川',

py : 'sichuan'

}

]

};

})

.controller('firstController',function($scope,Data,$filter){

$scope.data = Data;

$scope.today = new Date;

// 在控制器中使用,过滤器

var number = $filter('number')(3000);

console.log(number);

//json过滤器,主要用途是方便调试,看起来代码更加清楚

var jsonString = $filter('json')($scope.data);

console.log(jsonString);

console.log($scope.data);

//自动义过滤器,自定义一个方法解决过滤问题

$scope.checkName = function(obj){

if(obj.py.indexOf('h') === -1)

return false;

return true;

}

 

})

 

 

 

018~019 - 练习 过滤器 产品列表

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<link rel="stylesheet" href="../../vendor/bootstrap3/css/bootstrap.min.css"/>

<style>

.orderColor{

color:red;

}

</style>

</head>

<body>

<div ng-app="product">

 

<div class="container" ng-controller="productController">

<nav class="navbar navbar-default" role="navigation">

 

<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">

<form class="navbar-form navbar-left" role="search">

<div class="form-group">

<input type="text" ng-model="search.id" class="form-control" placeholder="Search">

</div>

</form>

</div>

</nav>

<table class="table">

<thead>

<tr>

<th ng-click="changeOrder('id')" ng-class="{dropup:order === ''}">

产品编号

<span ng-class="{orderColor:orderType === 'id'}" class="caret"></span>

</th>

<th ng-click="changeOrder('name')" ng-class="{dropup:order === ''}">

产品名称

<span ng-class="{orderColor:orderType === 'name'}" class="caret"></span>

</th>

<th ng-click="changeOrder('price')" ng-class="{dropup:order === ''}">

产品价钱

<span ng-class="{orderColor:orderType === 'price'}" class="caret"></span>

</th>

</tr>

</thead>

<tbody>

<!--filter:{id:search} order + orderType= -idid …… -->

<tr ng-repeat="product in productData | filter:search | orderBy:order + orderType">

<td>

{{product.id}}

</td>

<td>

{{product.name}}

</td>

<td>

{{product.price | currency : '(RMB)'}}

</td>

</tr>

</tbody>

</table>

</div>

</div>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

<script type="text/javascript" src="app/index.js"></script>

</body>

</html>

 

 

 

angular.module('product', [])

.service('productData', function () {

return [

{

id:3333,

name:'iphone',

price : 5400

},

{

id:885,

name:'ipad',

price : 3420

},

{

id:980,

name:'imac',

price : 15400

},

{

id:1212,

name:'ipad air',

price : 2340

},

{

id:3424,

name:'ipad mini',

price : 2200

}

];

})

.controller('productController', function ($scope,productData) {

$scope.productData = productData;

$scope.orderType = 'id';

$scope.order = '-';

$scope.changeOrder = function(type){

$scope.orderType = type;

if($scope.order === ''){

$scope.order = '-';

}else{

$scope.order = '';

}

}

});

 

 

 

 

自定义过滤器

 

  • module.filter(name, filterFactory)
  • @$filterProvider.register().

 

020-自定义过滤器、$controllerProvider使用

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

</head>

<body>

<div ng-app="myApp">

<div ng-controller="firstController">

<ul>

<li ng-repeat="user in data | filterAge">

{{user.name}}

{{user.age}}

{{user.city}}

</li>

</ul>

</div>

</div>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

<script type="text/javascript" src="app/index.js"></script>

</body>

</html>

 

 

var myApp = angular.module('myApp', [], function ($filterProvider, $provide, $controllerProvider) {

$provide.service('Data', function () {

return [

{

name: '张三',

age: '20',

city: '上海'

},

{

name: '李四',

age: '30',

city: '北京'

}

];

});

//第一种实现自定义过滤器的方法。

$filterProvider.register('filterAge', function () {

return function (obj) {

var newObj = [];

angular.forEach(obj, function (o) {

if (o.age > 20) {

newObj.push(o);

}

});

return newObj;

}

});

$controllerProvider.register('firstController', function ($scope, Data) {

$scope.data = Data;

})

})

//第二种实现自定义过滤器的方法,是使用模块的快捷方法实现自定义过滤器module.filter

.filter('filterCity',function(){

return function(obj){

var newObj = [];

angular.forEach(obj, function (o) {

if (o.city === '上海') {

newObj.push(o);

}

});

return newObj;

}

})

 

 

 

 

Controllers

 

angular controller

  • angular中,controller是一个javascript 函数(type/class),被用作扩展除了root scope在外的angular scope的实例。
  • 也可以通过module.controller(name, constructor)
  • @see $controllerProvider.register().
  • controller可以用作:
    设置scope对象的初始状态。
    增加行为到scope中。

 

 

 

正确的使用controller

  • controller不应该尝试做太多的事情。它应该仅仅包含单个视图所需要的业务逻辑
  • 保持Controller的简单性,常见办法是抽出那些不属于controller的工作到service中,在controller通过依赖注入来使用这些service

不要在Controller中做以下的事情:

 

  • 1.任何类型的DOM操作, controller应该仅仅包含业务逻辑,任何表现逻辑放到controller中,大大地影响了应用逻辑的可测试性。angular为了自动操作(更新)DOM,提供的数据绑定。如果希望执行我们自定义的DOM操作,可以把表现逻辑抽取到directive(指令)中。
  • 2.Input formatting(输入格式化) - 使用angular form controls 代替。
  • 3.Output filtering (输出格式化过滤) - 使用angular filters 代替。【输出格式化过滤使用filters】
  • 4.执行无状态或有状态的、controller共享的代码 - 使用angular services 代替。
  • 5.实例化或者管理其他组件的生命周期(例如创建一个服务实例)。【在模块中处理】

 

 

哪些事情在controller中做

  • 定义scope 中的数据,定义当前作用域中的数据
  • 定义方法,如:购物车中 的例子

 

 

021-控制器的合理使用、显示和隐示的依赖注入

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

</head>

<body>

<div ng-app="myApp">

<div ng-controller="secondController">

</div>

<div ng-controller="otherController">

</div>

</div>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

<script type="text/javascript" src="app/index.js"></script>

</body>

</html>

 

 

 

 

var myApp = angular.module('myApp', [], ['$filterProvider', '$provide', '$controllerProvider', function (a, b, c) {

console.log(a, b, c);

}])

.factory('CustomService', ['$window', function (a) {

console.log(a);

}])

// 隐示的依赖注入,js压缩,替换function中的参数,可能会出问题,不推荐这种写法。

.controller('firstController', function ($scope, CustomService) {

console.log(CustomService);

})

// 显示的依赖注入; 推荐这种写法,写在[] 里面

.controller('secondController', ['$scope', '$filter', function (a, b) {

console.log(b('json')([1, 2, 3, 4, 5]));

}]);

//这种写法不推荐

function otherController(a) {

console.log(a);

}

otherController.$inject = ['$scope'];

 

Directive

 

什么是指令

  • 可以利用指令来扩展HTML标签,增加声明式语法来实现想做的任何事,可以对应用有特殊意义的元素和属性来替换一般的HTML标签
  • angular也内置了非常多的指令,ng-appng-controller

 

 

指令和HTML校验

  • angular 内置指令的语法,以ng开始,代表angular命名空间,连接符后面的内容代表指令的名称
  • 指令的语法在很多HTML校验规则中是不合法的,Angular提供了多种调用指令方法,可以顺利通过不同校验的规则

 

校验器

格式

示例

none

namespace-name

ng-bind

XML

namespace:name

ng:bind

HTML5

data-namespace-name

data-ng-bind

XHTML

x-namespace-name

x-ng-bind

 

ng-bind这个指令有四种写法

 

指令的执行过程

  • 浏览器得到 HTML 字符串内容,解析得到 DOM 结构。
  • ng 引入,把 DOM 结构扔给 $compile 函数处理:
  • 找出 DOM 结构中有变量占位符
  • 匹配找出 DOM 中包含的所有指令引用
  • 把指令关联到 DOM
  • 关联到 DOM 的多个指令按权重排列
  • 执行指令中的 compile 函数(改变 DOM 结构,返回 link 函数)
  • 得到的所有 link 函数组成一个列表作为 $compile 函数的返回
  • 执行 link 函数(连接模板的 scope)。

 

 

Angular 内置指令

渲染指令

  • ng-init:【初始化数据】
  • ng-bind:【<p ng-bind="1+1"></p> 替换 <p>{{1+1}}</p> 这种写法】
  • ng-repeat
    $index
    当前索引【0,1,2, 之类的数字】
    $first
    是否为头元素 【true、false 布尔值】
    $middle
    是否为非头非尾元素
    $last
    是否为尾元素
  • ng-include 【加载另一个页面】
  • ng-bind-template:【可以自定义模板<p ng-bind-template="{{1+1}}"></p>

 

 

事件指令

内置事件指令的好处是:在处理完事件之后,帮你去自动的去实现脏检查()

  • ng-change
  • ng-click
  • ng-dblclick
  • ng-mousedown
  • ng-mouseenter
  • ng-mouseleave
  • ng-mousemove
  • ng-mouseover
  • ng-mouseup
  • ng-submit

 

 

节点指令

  • ng-style

  • ng-class
  • ng-class-evenng-class-odd【用在指令ng-repeat 里面的,奇数的时候用什么class,偶数的时候用什么class

  • ng-show
  • ng-hide

  • ng-switch:开关

  • ng-src :和ng-bind的原理类似,都是延迟加载

  • ng-href
  • ng-if 如果条件为true,就显示if 下面的内容

 

 

Demo 022~024-内置指令

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<style>

.red{

color:red;

}

</style>

</head>

<body>

<div ng-app="myApp">

<div ng-controller="firstController">

<p>{{1+1}}</p>

<p ng-bind="1+1">2</p>

<p ng-bind-template="{{1+1}}"></p>

<!-- $scope.cityArr = ['上海','北京','杭州'] -->

<ul ng-class="{red:status}" ng-init="cityArr = ['上海','北京','杭州']">

<li ng-class-even="'偶数'" ng-class-odd="'奇数'" ng-repeat="city in cityArr" >

<span>

index:{{$index}}

</span>

<span>

first:{{$first}}

</span>

<span>

middle:{{$middle}}

</span>

<span>

last :{{$last}}

</span>

<span>

{{city}}

</span>

</li>

</ul>

<div ng-include="'other.html'">

</div>

<div ng-include src="'other.html'">

</div>

<button ng-click="changeStatus($event)">点击切换</button>

<p>{{status}}</p>

<div ng-style="{color:'red'}" ng-hide="status">

你好!!!

</div>

<div ng-style="{color:'red'}" ng-show="status">

你好!!!

</div>

</div>

</div>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

<script type="text/javascript" src="app/index.js"></script>

</body>

</html>

 

 

 

var myApp = angular.module('myApp', [])

.controller('firstController', function ($scope) {

$scope.status = false;

 

$scope.changeStatus = function (event) {

// 通过element转换成 jquery对象;angularJs中提供了一些简单的jquery方法】

angular.element(event.target).html('切换状态为:' + $scope.status);

$scope.status = !$scope.status;

}

$scope.defaultStyle = {

color: 'red',

'margin-top': '50px'

};

$scope.src = 'http://www.angularjs.org/img/AngularJS-large.png';

})

 

 

 

 

 

Angular 自定义指令

 

指令的定义

  • module.directive(name, directiveFactory)
  • @see $compileProvider.directive()

 

 

指令的名字

  • 请不要使用ng为指令命名,这样可能会和angular内置指令冲突
  • 如果指令的名字为xxx-yyy 在设置指令的名字时应为xxxYyy 驼峰式声明法

 

 

指令定义选项

  • priority
  • terminal
  • scope
  • controller
  • controllerAs
  • require
  • restrict
  • template
  • templateUrl
  • replace
  • transclude
  • compile
  • link

 

 

restrict

  • restrict:指令在模版中的使用方式
  • 可以4种风格任意组合,如果忽略restrict,默认为A
  • 如果打算支持IE8,请使用基于属性和样式类的指令

 

字母

风格

示例

E

元素【可以当做标签来使用】

<my-dir></my-dir>

C

样式类

<span class="my-dir: exp;"></span>

A

属性

<span my-dir="exp"></span>

M

注释

<!-- directive: my-dir exp -->

 

 

template

  • template:模板内容,这个内容会根据 replace 参数的设置替换节点或只替换节点内容。

 

 

replace

  • replace:如果此配置为true则替换指令所在的元素,如果为false或者不指定,则把当前指令追加到所在的元素内部
  • 对于restrict为元素(E)在最终效果中是多余的,所有 replace通常设置为true

 

Demo 025-自定义指令 restrict、template、replace属性

 

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

</head>

<body>

<div ng-app="myApp">

<custom-tags>1212</custom-tags>

<div class="custom-tags">

</div>

<div custom-tags>

</div>

<!-- directive:custom-tags -->

</div>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

<script type="text/javascript" src="app/index.js"></script>

</body>

</html>

 

 

var myApp = angular.module('myApp', [], ['$compileProvider',function ($compileProvider) {

$compileProvider.directive('customTags',function(){

return {

restrict:'ECAM',

template:'<div>custom-tags-html</div>',

replace:true,

compile:function(){

console.log(1);//打印四次

}

}

});

}])

//.directive('')

 

 

 

 

 

templateUrl

  • templateUrl:加载模版所要使用的URL
  • 可以加载当前模板内对应的的text/ng-template script id
  • 在使用chrome浏览器时,"同源策略"会阻止chromefile://中加载模版,并显示一个"Access-Control-Allow-Origin" 不允许源为null , 可以把项目放在服务器上加载,或者给Chrome设置一个标志,命令为:
    chrome
    allow-file-access-from-files

 

 

transclude

  • transclude:指令元素中的原来的子节点移动到一个新模版内部
  • 当为true时,指令会删掉原来的内容,使你的模版可以用ng-transclude指令进行重新插入

 

Demo 026-自定义指令 templateUrl属性

 

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

</head>

<body>

<div ng-app="myApp">

<script type="text/ng-template" id="customTags2">

<div>

hello {{name}}

</div>

</script>

<div ng-controller="firstController">

<custom-tags></custom-tags>

<custom-tags2></custom-tags2>

</div>

</div>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

<script type="text/javascript" src="app/index.js"></script>

</body>

</html>

 

 

var myApp = angular.module('myApp', [])

.directive('customTags', function () {

return {

restrict: 'ECAM',

templateUrl: 'tmp/other.html',//【引用其他页面,页面内容要用标签包含,不能事纯文本】

replace: true

}

})

.directive('customTags2', function () {

return {

restrict: 'ECAM',

templateUrl: 'customTags2',

replace: true

}

})

.controller('firstController', ['$scope', function ($scope) {

$scope.name = '张三';

}]);

 

priority && terminal

  • priority:设置指令在模版中的执行顺序,顺序是相对于元素上其他执行而言,默认为0,从大到小的顺序依次执行
  • 设置优先级的情况比较少,象ng-repeat,在遍历元素的过程中,需要angular先拷贝生成的模版元素,在应用其他指令,所以ng-repeat默认的priority1000
  • terminal 是否以当前指令的权重为结束界限。如果这值设置为 true ,则节点中权重小于当前指令的其它指令不会被执行。相同权重的会执行。

 

Demo 027-自定义指令 transclude、priority、terminal属性

 

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

</head>

<body>

<div ng-app="myApp">

<div ng-controller="firstController">

<custom-tags>原始数据</custom-tags>

<div custom-tags2 custom-tags3>

</div>

</div>

</div>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

<script type="text/javascript" src="app/index.js"></script>

</body>

</html>

 

var myApp = angular.module('myApp', [])

.directive('customTags', function () {

return {

restrict: 'ECAM',

template:'<div>新数据 <span ng-transclude></span></div>',

replace: true,

transclude:true

}

})

.directive('customTags2', function () {

return {

restrict: 'ECAM',

template:'<div>2</div>',

replace: true,

priority:-1

}

})

.directive('customTags3', function () {

return {

restrict: 'ECAM',

template:'<div>3</div>',

replace: true,

priority: 0,

// 小于0 directive 都不会执行

terminal:true

}

})

.controller('firstController', ['$scope', function ($scope) {

$scope.name = '张三';

}]);

 

Angularjs 指令编译三阶段【重点】

  • 1. 标准浏览器API转化
    html转化成dom,所以自定义的html标签必须符合html的格式
  • 2. Angular compile
    搜索匹配directive,按照priority排序,并执行directive上的compile方法
  • 3. Angular link
    执行directive上的link方法,进行scope绑定及事件绑定

 

 

为什么编译的过程要分成compilelink?

  • 简单的说就是为了解决性能问题,特别是那种model变化会影响dom结构变化的,而变化的结构还会有新的scope绑定及事件绑定,比如ng-repeat

 

 

compilelink的使用时机

  • Compile修改dom结构】
    想在
    dom渲染前对它进行变形,并且不需要scope参数
    想在所有相同directive里共享某些方法,这时应该定义在compile里,性能会比较好
    返回值就是linkfunction,这时就是共同使用的时候
  • Link 【绑定事件】
    对特定的元素注册事件
    需要用到scope参数来实现dom元素的一些行为

 

 

compile

  • complie:function(tElement,tAttrs,transclude)
  • complie函数用来对模版自身进行转换,仅仅在编译阶段运行一次
  • complie中直接返回的函数是postLink,表示link参数需要执行的函数,也可以返回一个对象里面包含preLinkpostLink
  • 当定义complie参数时,将无视link参数,因为complie里返回的就是该指令需要执行的link函数

 

 

link

  • link(scope,iElement,iAttrs,controller)
  • link参数代表的是complie返回的postLink
  • preLink 表示在编译阶段之后,指令连接到子元素之前运行
  • postLink 表示会在所有子元素指令都连接之后才运行
  • link函数负责在模型和视图之间进行动态关联,对于每个指令的每个实例,link函数都会执行一次

 

Demo 028-自定义指令 compile && link属性

 

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

</head>

<body>

<div ng-app="myApp">

<div ng-controller="firstController">

<!--

1. div 转换为dom结构

2. 默认的优先级为0,哪个先定义哪个先使用

-->

<div ng-repeat="user in users" custom-tags="" custom-tags2>

</div>

</div>

</div>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

<script type="text/javascript" src="app/index.js"></script>

</body>

</html>

 

 

 

var i = 0;

var myApp = angular.module('myApp', [])

.directive('customTags',function(){

return {

restrict : 'ECAM',

template : '<div>{{user.name}}</div>',

replace : true,

//tElement 当前元素的 element,当前元素的jquery对象

//tAttrs 当前元素的一些属性

compile:function(tElement,tAttrs,transclude){//【有了compile之后,定义link就没有用了,因为,compile中也包含了link

tElement.append(angular.element('<div>{{user.name}}{{user.count}}</div>'));

// 编译阶段...

console.log('customTags compile 编译阶段...');

return {

// 表示在编译阶段之后,指令连接到子元素之前运行

pre:function preLink(scope,iElement,iAttrs,controller){

console.log('customTags preLink..')

},

// 表示在所有子元素指令都连接之后才运行

post:function postLink(scope,iElement,iAttrs,controller){

 

iElement.on('click',function(){

scope.$apply(function(){//apply方法触发脏检查】

scope.user.name = 'click after';

scope.user.count = ++i;

// 进行一次 脏检查

});

})

 

console.log('customTags all child directive link..')

}

}

// 可以直接返回 postLink

// return postLink function(){

// console.log('compile return fun');

//}

},

// link表示的就是 postLink【因为在 compile中已经定义了link,故而,这里没有必要再定义】

link:function(){

// iElement.on('click',function(){

// scope.$apply(function(){

// scope.user.name = 'click after';

// scope.user.count = ++i;

// // 进行一次 脏检查

// });

// })

}

}

})

 

.directive('customTags2',function(){

return {

restrict : 'ECAM',

replace : true,

compile:function(){

// 编译阶段...

console.log('customTags2 compile 编译阶段...');

 

return {

// 表示在编译阶段之后,指令连接到子元素之前运行

pre:function preLink(){

console.log('customTags2 preLink..')

},

// 表示在所有子元素指令都连接之后才运行

post:function postLink(){

console.log('customTags2 all child directive link..')

}

}

 

}

}

})

.directive('customTags3',function(){ // return postLink;

return function(){

}

})

.controller('firstController', ['$scope', function ($scope) {

$scope.users = [

{

id:10,

name:'张三'

},

{

id:20,

name:'李四'

}

];

}]);

 

 

 

 

controller && controllerAs && require

  • controller 他会暴露一个API,利用这个API可以在多个指令之间通过依赖注入进行通信(作用)
  • controller($scope,$element,$attrs,$transclude)
  • controllerAs 是给controller起个别名,方便使用
  • require 可以将其他指令传递给自己

 

选项

用法

directiveName

通过驼峰法的命名指定了控制器应该带有哪一条指令,默认会从同一个元素上的指令

^directiveName

在父级查找指令

?directiveName

表示指令是可选的,如果找不到,不需要抛出异常

 

 

Demo 029-自定义指令 controller && controllAs属性

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

</head>

<body>

<div ng-app="myApp">

<div ng-controller="firstController">

<div book-list>

</div>

</div>

</div>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

<script type="text/javascript" src="app/index.js"></script>

</body>

</html>

 

 

 

angular.module('myApp', [])

.directive('bookList', function () {

return {

restrict: 'ECAM',

controller: function ($scope) {

$scope.books = [

{

name: 'php'

},

{

name: 'javascript'

},

{

name: 'java'

}

];

$scope.addBook = function(){

}

this.addBook = function(){

// ...

}

},

controllerAs:'bookListController',//【相当于给上面的controller起一个别名,在link函数中有引用】

template: '<ul><li ng-repeat="book in books">{{book.name}}</li></ul>',

replace:true,

link:function(scope,iEelement,iAttrs,bookListController){

iEelement.on('click',bookListController.addBook)

}

}

})//【这里不要给分号,给了后面就不能.controller了,就不能链式操作了】

//不写全,代码压缩会报错

.controller('firstController', ['$scope', function ($scope) {

// console.log($scope);

}]);

 

 

 

 

Demo 030-自定义指令 require 属性

 

 

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

</head>

<body>

<div ng-app="myApp">

<div ng-controller="firstController">

<div book-list>

</div>

</div>

</div>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

<script type="text/javascript" src="app/index.js"></script>

</body>

</html>

 

 

angular.module('myApp', [])

.directive('bookList', function () {

return {

restrict: 'ECAM',

controller: function ($scope) {

$scope.books = [

{

name: 'php'

},

{

name: 'javascript'

},

{

name: 'java'

}

];

this.addBook = function(){

$scope.$apply(function(){

$scope.books.push({

name:'Angularjs'

})

});

}

},

controllerAs:'bookListController',

template: '<div><ul><li ng-repeat="book in books">{{book.name}}</li></ul><book-add></book-add></div>',

replace:true

}

})

.directive('bookAdd',function(){

return {

restrict:'ECAM',

require:'^bookList',//^directiveName 带有^ 符号,表示在父级查找指令】

template:'<button type="button">添加</button>',

replace:true,

link:function(scope,iElement,iAttrs,bookListController){

iElement.on('click',bookListController.addBook);

}

}

})

.controller('firstController', ['$scope', function ($scope) { // console.log($scope);

}]);

 

 

 

 

scope

  • scope:为当前指令创建一个新的作用域,而不是使之继承父作用域
  • false 继承父元素的作用域
    true
    创建一个新的作用域
    object
    独立的scope
  • object:参数
    &:
    作用域把父作用域的属性包装成一个函数,从而以函数的方式读写父作用域的属性
    =:
    作用域的属性与父作用域的属性进行双向绑定,任何一方的修改均影响到对方
    @:
    只能读取父作用域里的值单项绑定【只能是简单类型,不能是引用类型的,不能是对象】

写的多了自然而然就理解了, angularjs 难点在于指令之间的架构

 

Demo 031 - 自定义指令 scope 属性

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

</head>

<body>

<div ng-app="myApp">

<div ng-controller="firstController">

{{

books

}}

<div book-list books="books" parent-books="books" parent-title="{{title}}">

</div>

</div>

</div>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

<script type="text/javascript" src="app/index.js"></script>

</body>

</html>

 

 

 

angular.module('myApp', [])

.directive('bookList', function () {

return {

restrict: 'ECAM',

controller: function ($scope) {

// &books

// $scope.books = $scope.a();

//================================================================

// =books;

// $scope.books = $scope.b;

// $scope.b.push({name:'nodejs'});

//================================================================

console.log($scope.c);

},

// scope:true, 创建一个有继承链的独立作用域

/ /scope:false, 不创建作用域,继承父元素的作用域

 

// 当为对象的时候也会创建一个独立的作用域

scope:{

// & 将父元素 books 封装成一个a函数

// a:'&books'

//================================================================

// = 双向绑定 b = parentBooks属性对应的父作用域的表达式

// b:'=parentBooks'

//================================================================

// @ 只能引用父元素的简单类型的属性

c:'@parentTitle'

},

controllerAs:'bookListController',

template: '<div><ul><li ng-repeat="book in books">{{book.name}}</li></ul></div>',

replace:true

}

})

.controller('firstController', ['$scope', function ($scope) {

console.log($scope);

$scope.books = [

{

name: 'php'

},

{

name: 'javascript'

},

{

name: 'java'

}

];

$scope.title = '张三';

}]);

 

 

Demo 032 - 练习 自定义accordion指令 skip

 

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<link rel="stylesheet" href="../../vendor/bootstrap3/css/bootstrap.min.css"/>

</head>

<body>

<div ng-app="myApp">

<div class="container">

<div ng-controller="firstController">

<kittencup-group>

<kittencup-collapse ng-repeat="collapse in data" heading="{{collapse.title}}">

{{collapse.content}}

</kittencup-collapse>

</kittencup-group>

</div>

</div>

</div>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

<script type="text/javascript" src="app/index.js"></script>

</body>

</html>

 

 

 

angular.module('myApp', [])

// 数据

.factory('Data', function () {

return [

{

title: 'no1',

content: 'no1-content'

},

{

title: 'no2',

content: 'no2-content'

},

{

title: 'no3',

content: 'no3-content'

}

];

})

// 控制器

.controller('firstController', ['$scope','Data',function ($scope,Data) {

$scope.data = Data;

}])

 

.directive('kittencupGroup',function(){

return {

restrict:'E',

replace:true,//【该标签不符合w3c 规范,肯定要替换掉它】

template:'<div class="panel-group" ng-transclude></div>',

transclude:true,

controllerAs:'kittencupGroupContrller',

controller:function(){

this.groups = [];

this.closeOtherCollapse = function(nowScope){

angular.forEach(this.groups,function(scope){

if(scope !== nowScope){

scope.isOpen = false;

}

})

}

}

}

})

 

.directive('kittencupCollapse',function(){

return {

restrict:'E',

replace:true,

require:'^kittencupGroup',

templateUrl:'app/tmp/kittencupCollapse.html',//【因为,模板代码比较长,故而,用另外一个页面】

scope:{

heading:'@'

},

link:function(scope,element,attrs,kittencupGroupContrller){

scope.isOpen = false;

scope.changeOpen = function(){

scope.isOpen = !scope.isOpen;

kittencupGroupContrller.closeOtherCollapse(scope);

}

kittencupGroupContrller.groups.push(scope);

},

transclude:true

}

})

 

 

<div class="panel panel-default">

<div class="panel-heading" ng-click="changeOpen()">

<h4 class="panel-title">

<a href="#">

{{heading}}

</a>

</h4>

</div>

<div class="panel-collapse" ng-class="{collapse:!isOpen}">

<div class="panel-body" ng-transclude>

</div>

</div>

</div>

 

 

 

Module里的一些其他方法

 

constant

  • constant(name,object)
  • 此方法首先运行,可以用它来声明整个应用范围内的常量,并且让它们在所有配置(config方法里)和实例(controller,service)方法中都可用

 

 

value

  • value(name,object)
  • 如果只想在服务内得到一些内容,可以通过value来申明常量

 

 

run

  • run(initializationFn)
  • 想要在注入启动之后执行某些操作,而这些操作需要在页面对用户可用之前执行,可以使用此方法
  • 比如加载远程的模版,需要在使用前放入缓存,或者在使用操作前判断用户是否登录,未登录可以先去登陆页面

 

 

Demo 033 - 模块里的constant、value、run方法

 

angular.module('myApp',[],['$provide',function($provide){

console.log('config');

// $provide.factory

// $provide.service

// $provide.constant

// $provide.value;//provide中的方法 都会有快捷方法】

 

}])

 

.config(function(APIKEY){

console.log(APIKEY);

console.log('config');

})

 

// config之后controller等其他服务之前,执行此方法。。

.run(function(){

console.log('run');

})

// 它只是可以注入任何方法

.constant('APIKEY','xxxx')

// 只能注入controller...service factory。【在config中无法注入该方法】

.value('vension','1.0.0')

 

.controller('firstController',['APIKEY','vension',function(APIKEY,vension){

console.log(APIKEY);

console.log(vension);

console.log('controller');

}]);

 

 

Form表单

  • 一般来讲表单可能遇到的问题
    1.
    如何数据绑定
    2.
    验证表单
    3.
    显示出错信息
    4.
    整个Form的验证
    5.
    避免提交没有验证通过的表单
    7.
    防止多次提交

 

 

input type 扩展

  • number
  • url
  • email
  • reset

 

 

input 属性

  • name 名字
  • ng-model 绑定的数据

    ng-model="data.username" 数据绑定在data.username

  • ng-required 是否必填

    ng-required="true" 值为true 表示必填项

  • ng-minlength 最小长度
  • ng-maxlength 最大长度
  • ng-pattern 匹配模式
  • ng-change 值变化时的回调

 

 

CSS样式

  • ng-valid 当表单验证通过时的设置
  • ng-invalid 表单验证失败时的设置
  • ng-pristine 表单的未被动之前拥有
  • ng-dirty 表单被动过之后拥有

 

 

Form控制变量

  • 字段是否未更改
    formName.inputFieldName.$pristine
  • 字段是否更改
    formName.inputFieldName.$dirty
  • 字段有效
    formName.inputFieldName.$valid
  • 字段无效
    formName.inputFieldName.$invalid

    当表单的字段无效,该字段为true

  • 字段错误信息
    formName.inputfieldName.$error

    Form名字. 表单名字 获取表单的错误信息

 

 

属性

描述

$dirty

表单有填写记录

$valid

字段内容合法的

$invalid

字段内容是非法的

$pristine

表单没有填写记录

 

 

 

From 方法

  • $setPristine 将表单复位原始状态,class,$dirty,$pristine

 

 

ng-model

  • ng-modelangular原生的directive
  • 可以通过require ngModel 可以更深入的去处理数据的双向绑定

 

 

ngModel 里的属性

  • $parsers属性 保存了从viewValuemodelValue绑定过程中的处理函数,它们将来会依次执行
  • $formatters 它保存的是从modelValueviewValue绑定过程中的处理函数
  • $setViewValue view发生了某件事情时,从viewmodel绑定调用$setViewValue viewValue保存下来
  • $render 当模型发生变化时,应该怎么去更新视图,从modelview绑定,调用ctrl.$render方法,将viewValue渲染到页面上
  • $setValidity 设置验证结果
  • $viewValue 视图的值
  • $modelValue 模型里的值

 

 

XHR和服务器端的通信

 

$http

  • $http 是一个服务,简单的封装了XMLHttpRequest对象
  • $http(config).success(fun).error(fun)

 

 

$http短名方法

  • $http.get()
  • $http.delete()
  • $http.header()
  • $http.jsonp()
  • $http.post()
  • $http.put()

 

 

$http 配置对象

  • method
  • url
  • params
  • data
  • headers
  • xsrfHeaderName
  • xsrfCookieName
  • transformRequest
  • transformResponse
  • cache
  • withCredentials
  • timeout
  • responseType

 

 

responseType

  • " (string default)
  • "arraybuffer" (ArrayBuffer)
  • "blob" (blob object)
  • "document" (HTTP document)
  • "json" (JSON object parsed from a JSON string)
  • "text" (string)
  • "moz-blob" (Firefox to receive progress events)
  • "moz-chunked-text" (streaming text)
  • "moz-chunked-arraybuffer" (streaming ArrayBuffer)

 

 

Demo 034-Form

 

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<link rel="stylesheet" href="../../vendor/bootstrap3/css/bootstrap.min.css"/>

</head>

<body>

<div ng-app="myApp" style="margin-top: 100px;">

<form name="myForm" action="kittencup.php" ng-controller="firstController" class="container form-horizontal">

<div class="form-group" ng-class="{'has-error':myForm.username.$dirty && myForm.username.$invalid}">

<label class="col-sm-2 control-label">用户名</label>

<div class="col-sm-10">

<input type="text" autocomplete="off" name="username" ng-pattern="/^[a-zA-Z]{1}/" ng-required="true" ng-minlength="5" ng-maxlength="10" ng-model="data.username" class="form-control" placeholder="用户名">

<div ng-show="myForm.username.$dirty && myForm.username.$error.maxlength" class="alert alert-danger help-block">

用户名长度不能超过10

</div>

<div ng-show="myForm.username.$dirty && myForm.username.$error.minlength" class="alert alert-danger help-block">

用户名长度不能小于5

</div>

<div ng-show="myForm.username.$dirty && myForm.username.$error.pattern" class="alert alert-danger help-block">

用户名必须已英文字母开始

</div>

</div>

</div>

<div class="form-group" ng-class="{'has-error':myForm.password.$dirty && myForm.password.$invalid}">

<label class="col-sm-2 control-label"> </label>

<div class="col-sm-10">

<input type="password" autocomplete="off" name="password" ng-required="true" ng-minlength="5" ng-maxlength="10" ng-model="data.password" class="form-control" placeholder="密码">

<div ng-show="myForm.password.$dirty && myForm.password.$error.maxlength" class="alert alert-danger help-block">

密码长度不能超过10

</div>

<div ng-show="myForm.password.$dirty && myForm.password.$error.minlength" class="alert alert-danger help-block">

密码长度不能小于5

</div>

</div>

</div>

 

<div class="form-group" ng-class="{'has-error':myForm.passwordConfirm.$dirty && myForm.passwordConfirm.$invalid}">

<label class="col-sm-2 control-label">确认密码</label>

<div class="col-sm-10">

<input type="password" autocomplete="off" name="passwordConfirm" ng-required="true" ng-model="data.passwordConfirm" class="form-control" placeholder="确认密码">

<div ng-show="myForm.password.$dirty && myForm.passwordConfirm.$dirty && data.password !== data.passwordConfirm" class="alert alert-danger help-block">

密码和确认密码不一致

</div>

</div>

</div>

 

<div class="form-group" ng-class="{'has-error':myForm.email.$dirty && myForm.email.$invalid}">

<label class="col-sm-2 control-label">邮箱</label>

<div class="col-sm-10">

<input type="email" autocomplete="off" name="email" ng-required="true" ng-minlength="5" ng-maxlength="30" ng-model="data.email" class="form-control" placeholder="邮箱">

<div ng-show="myForm.email.$dirty && myForm.email.$error.maxlength" class="alert alert-danger help-block">

邮箱长度不能超过30

</div>

<div ng-show="myForm.email.$dirty && myForm.email.$error.minlength" class="alert alert-danger help-block">

邮箱长度不能小于5

</div>

<div ng-show="myForm.email.$dirty && myForm.email.$error.email" class="alert alert-danger help-block">

邮箱格式不正确

</div>

</div>

</div>

 

<div class="form-group" ng-class="{'has-error':myForm.blog.$dirty && myForm.blog.$invalid}">

<label class="col-sm-2 control-label">博客网址</label>

<div class="col-sm-10">

<input type="url" autocomplete="off" name="blog" ng-required="true" ng-minlength="5" ng-maxlength="30" ng-model="data.blog" class="form-control" placeholder="博客网址">

<div ng-show="myForm.blog.$dirty && myForm.blog.$error.maxlength" class="alert alert-danger help-block">

网址长度不能超过30

</div>

<div ng-show="myForm.blog.$dirty && myForm.blog.$error.minlength" class="alert alert-danger help-block">

网址长度不能小于5

</div>

<div ng-show="myForm.blog.$dirty && myForm.blog.$error.url" class="alert alert-danger help-block">

网址格式不正确

</div>

</div>

</div>

 

<div class="form-group" ng-class="{'has-error':myForm.age.$dirty && myForm.age.$invalid}">

<label class="col-sm-2 control-label">年龄</label>

<div class="col-sm-10">

<input type="number" autocomplete="off" name="age" min="10" max="99" ng-required="true" ng-model="data.age" class="form-control" placeholder="年龄">

<div ng-show="myForm.age.$dirty && myForm.age.$error.max" class="alert alert-danger help-block">

年龄不能超过99

</div>

<div ng-show="myForm.age.$dirty && myForm.age.$error.min" class="alert alert-danger help-block">

年龄不能小于10

</div>

</div>

</div>

 

<div class="form-group">

<label class="col-sm-2 control-label">性别</label>

<div class="col-sm-10">

<label class="radio-inline">

<input type="radio" ng-required="true" name="sex" ng-model="data.sex" value="1" />

</label>

<label class="radio-inline">

<input type="radio" ng-required="true" name="sex" ng-model="data.sex" value="0" />

</label>

</div>

</div>

 

<div class="form-group">

<label class="col-sm-2 control-label">爱好</label>

<div class="col-sm-10">

<label class="checkbox-inline" ng-repeat="hobby in hobbies">

<input type="checkbox" ng-model="hobby.checked" name="hobby[]" ng-checked="data.hobbies === undefined ? false : data.hobbies.indexOf(hobby.id) !== -1" ng-click="toggleHobbySelection(hobby.id)"/> {{hobby.name}}

</label>

</div>

</div>

 

<div class="form-group">

<label class="col-sm-2 control-label">出生地</label>

<div class="col-sm-3">

<select class="form-control" ng-change="data.area = false" ng-model="data.province" ng-options="x.id as x.name for x in cities | cityFilter:0"></select>

</div>

<div class="col-sm-3">

<select class="form-control" ng-show="data.province" ng-model="data.area" ng-options="x.id as x.name for x in cities | cityFilter:data.province"></select>

</div>

<div class="col-sm-3">

<select class="form-control" ng-required="true" ng-show="data.province && data.area" ng-model="data.city" ng-options="x.id as x.name for x in cities | cityFilter:data.area"></select>

</div>

</div>

 

<div class="form-group">

<label class="col-sm-2 control-label">只能输入偶数</label>

<div class="col-sm-10">

<input type="text" name="even" class="form-group" placeholder="偶数" ng-model="data.even" even>

<div ng-show="myForm.even.$error.even" class="alert alert-danger help-block">

数字必须是偶数

</div>

</div>

</div>

 

<div class="form-group">

<label class="col-sm-2 control-label">个人介绍</label>

<div class="col-sm-10">

<custom-text-area ng-model="data.introduct">aaa</custom-text-area>

<custom-text-area ng-model="data.introduct"></custom-text-area>

</div>

</div>

 

<div class="form-group">

<div class="col-sm-offset-2 col-sm-10">

<button type="submit" class="btn btn-default" ng-disabled="myForm.$invalid || data.hobbies === undefined || data.hobbies.length === 0">注册</button>

<button type="reset" class="btn btn-default" ng-click="reset()">重置</button>

</div>

 

</div>

</form>

</div>

<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>

<script type="text/javascript" src="app/index.js"></script>

</body>

</html>

 

 

 

angular.module('myApp', [])

 

.filter('cityFilter', function () {

return function (data, parent) {

var filterData = [];

angular.forEach(data, function (obj) {

if (obj.parent === parent) {

filterData.push(obj);

}

})

return filterData;

}

})

.directive('even',function(){

return {

require : 'ngModel',

link:function(scope,elm,attrs,ngModelController){

ngModelController.$parsers.push(function(viewValue){

if(viewValue % 2 === 0){

ngModelController.$setValidity('even',true);

}else{

ngModelController.$setValidity('even',false);

}

return viewValue;

});

 

// ngModelController.$formatters.push(function(modelValue){

// return modelValue + 'kittencup';

// })

}

};

})

 

.directive('customTextArea',function(){

return {

restrict:'E',

template:'<div contenteditable="true"></div>',

replace:true,

require : 'ngModel',

link:function(scope,elm,attrs,ngModelController){

 

 

// view->model

elm.on('keyup',function(){

scope.$apply(function(){

ngModelController.$setViewValue(elm.html());

});

})

 

ngModelController.$render = function(){

elm.html(ngModelController.$viewValue);

}

 

}

};

})

 

 

.controller('firstController', ['$scope', function ($scope) {

 

var that = this;

 

$scope.hobbies = [

{

id: 1,

name: '玩游戏'

},

{

id: 2,

name: '写代码'

},

{

id: 3,

name: '睡觉'

},

];

 

$scope.cities = [

{

name: '上海',

parent: 0,

id: 1

},

{

name: '上海市',

parent: 1,

id: 2

},

{

name: '徐汇区',

parent: 2,

id: 8

},

{

name: '长宁区',

parent: 2,

id: 3

},

{

name: '北京',

parent: 0,

id: 4

},

{

name: '北京市',

parent: 4,

id: 5

},

{

name: '东城区',

parent: 5,

id: 6

},

{

name: '丰台区',

parent: 5,

id: 7

},

{

name: '浙江',

parent: 0,

id: 9

},

{

name: '杭州',

parent: 9,

id: 100

},

{

name: '宁波',

parent: 9,

id: 11

},

{

name: '西湖区',

parent: 100,

id: 12

},

{

name: '北仑‎',

parent: 11,

id: 13

}

];

 

 

$scope.data = {

hobbies: [1, 2],

city: 3

};

 

 

// 先保留一份默认值

$scope.origData = angular.copy($scope.data);

 

$scope.reset = function(){

 

$scope.data = angular.copy($scope.origData);

that.initCity();

$scope.myForm.$setPristine();

}

 

// 让城市关联使用

this.findCityId = function (parent) {

var parentId;

angular.forEach($scope.cities, function (city) {

if (city.id === parent) {

parentId = city.parent;

return;

}

})

 

return parentId;

}

 

this.initCity = function(){

if ($scope.data.city !== undefined) {

$scope.data.area = this.findCityId($scope.data.city);

$scope.data.province = this.findCityId($scope.data.area);

}

}

 

// 第一次打开页面 需要初始化一下

this.initCity.call(this);

 

$scope.toggleHobbySelection = function (id) {

 

var index = -1;

if ($scope.data.hobbies === undefined) {

$scope.data.hobbies = [];

} else {

index = $scope.data.hobbies.indexOf(id);

}

 

if (index === -1) {

$scope.data.hobbies.push(id);

} else {

$scope.data.hobbies.splice(index, 1);

}

 

}

}]);

 

 

路由

使用AngularUI库 实现路由

 

 

AngularUI库提供的最有用的库之一便是ui-router。它是一个路由框架,允许你通过状态机
组织接口,而不是简单的URL路由。

 

 

你还要确保在视图中链接这个库:
<scripttype="text/javascript" src="app/bower_components/angular-ui-router/release/angular-ui-router.js"></script>


同时还需要将ui.router作为依赖注入到你的应用中:
angular.module('myApp', ['ui.router']);


现在,不同于内置的ngRoute服务,由于ui-router基于状态工作,而不是简单的url,因此
你可以将它嵌套在视图中。
在处理ngRoute服务时我们不再使用ng-view,而改为使用ui-view指令。
在ui-router内处理路由和状态时,我们主要关心的是应用程序处在哪个状态以及Web应用
当前处在哪个路由位置。
<div ng-controller="DemoController">
<div ui-view></div>
</div>
和ngRoute一样,定义在任意给定状态内的模板都处在<div ui-view></div>元素内。此外,
每个模板都可以包含自己的ui-view。 这事实上就允许你在路由中嵌套视图。
为了定义路由,你可以使用.config方法,和常见的方式一样,但不是将路由设置在
$routeProvider上,而是将状态设置在$stateProvider上。
.config(function($stateProvider,$urlRouterProvider) {
$stateProvider
.state('start', {
url: '/start',
templateUrl: 'partials/start.html'
})
});
这一步给状态配置对象分配了一个名为start的状态。这个状态配置对象,或者说这个
stateConfig

stateProvider
.state('inbox', {
url: '/inbox',
template: '<h1>Welcome to your inbox</h1>'
});
当用户导航到/inbox时,应用会转换到inbox状态,然后使用模板内容(<h1>Welcome to your
inbox</h1>)填充主要的ui-view指令。

 

 

//当用户导航到url:/main时,使用templateUrl填充ui-view指令。
.state('main', {
url: '/main',
controller: "HeaderCtrl",
templateUrl: 'views/main.html'
})

2. controller


ngRoute一样,你可以给已经注册好的控制器关联一个URL(使用字符串),也可以创建一
个控制器函数作为状态控制器。
如果没有定义模板(使用上述方式之一),就不会创建这个控制器。

 

3.URL

 

URL可以接受一系列不同的选项,它还可以在url中设置基本的参数,就像在ngRoute中一样:

$stateProvider
.state('inbox', {
url: '/inbox/:inboxId',
template: '<h1>Welcome to your inbox</h1>',
controller: function($scope, $stateParams) {
$scope.inboxId = $stateParams.inboxId;
}
});

 

参考

AngularJs 权威教程 第25章

原文地址:https://www.cnblogs.com/weiqinshian/p/6719416.html