• 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章

  • 相关阅读:
    c++之输出文件和输入文件的处理
    C++之输入输出流
    c++之虚析构函数
    c++之虚函数和基类指针
    接口自动化测试框架Karate入门
    uiautomator+cucumber实现移动app自动化测试
    calabash-android Win10 入门笔记
    Page Object 模式编写UiAutomator脚本
    ruby脚本打印日志到rspec的报告文件中
    Ruby跳出多层循环 catch...throw
  • 原文地址:https://www.cnblogs.com/weiqinshian/p/6719416.html
Copyright © 2020-2023  润新知