angularjs 知识点
1. $eval 方法对绑定的属性值直接进行解析
<input type='text' ng-model = 'expr2/> <span ng-bing='$eval(expr2)'></span> $scope.expr2 = '20 + 1 | number:0';
2. ng-repeat
指令复制元素-在复制过程中可以添加元素相应的属性-专有变量
$first
$last
$middle
$index
<span>{{$first?'yes':'no"}}</span
3. 添加元素样式
$scope.red = "red"; <div ng-class="{{red}}"></div> <div class="{{red}}"></div>
字符串数组形式添加样式
$scope.blnfocus = false; <div ng-class="{true:'red',false:'green'}[blnfocus]"></div>
定义key/value对象的方式添加多个css样式
$scope.a = false; $scope.b = true; <div ng-class="{'red':a,'green':b}"></div>
4. 控制元素显示,隐藏状态
页面中调用ng-show,ng-hide,ng-switch指令绑定$scope对象的属性值
ng-switch 指令中 on可有可无,当on于多个或某个ng-switch-when指令的元素匹配时,这些元素显示,如果没有匹配的ng-switch-default显示.
<div ng-show = {{isShow}}> div </div> <div ng-hide = {{isHide}}>hide</div> <ul ng-switch on={{switch}}> <li ng-switch-when="1">taoguorong</li> <li ng-switch -default>more</li> </ul>
5. 表单基本验证功能
$pristine:表单或控件内容是否未输入过
$dirty:表单或控件内容是否已输入过
$valid:表单或控件内容是否已验证通过
$invalid:表单或空间内容是否未验证通过
$error:表单或控件验证时的错误提示信息
<form name="temp_form" ng-submit="save()"> <div> <input name="t_email" ng-model = "email" type="email" required/> <span ng-show="temp_form.t_email.$error.required> 邮件不能为空 </span> <span ng-show="temp_form.t_email.$error.email> 邮件格式不对 </span </div> <input type = "button" ng-disabled="temp_form.$invalid" value="提交"/> </form>
6. 表单中的checkbox控件和redio控件
通过ng-model绑定控制器的属性,一旦绑定完成,首次加载时,将以绑定的值作为控件的初始化状态.
<form name="temp_form" ng-submit="save()"> <div> <input name="t_email" ng-model = "email" type="email" required/> <span ng-show="temp_form.t_email.$error.required> 邮件不能为空 </span> <span ng-show="temp_form.t_email.$error.email> 邮件格式不对 </span </div> <div> <input type="checkbox" ng-model = "a" ng-true-value="同意" ng-false-value = "不同意">同意 </div> <div> <input type="rediio" ng-model = "a" value="男">男 <input type="rediio" ng-model = "a" value="女">女 </div> <input type = "button" ng-disabled="temp_form.$invalid" value="提交"/> </form>
ng-true-value表示选中后返回的值,后者表示没有被选中时返回的值,redio只有被选中的会返回其被选中的值.
7. 表单中的select控件
可以借助ng-option指令属性,将数组,对象类型的数据添加到<option>元素中,同时还能在添加数据时进行分组显示.
绑定简单的数据类型:
通过ng-option指令属性值,采用...for...in...格式将数组与<select>控件绑定
绑定简单的对象数据
通过ng-option指令属性值,采用...as...for...in...格式将对象与<select>控件绑定,as前面部分对应元素的value值,用于选中时获取,as后面部分对应元素的text值,用于直接显示
以分组的形式绑定对象数据
通过ng-option指令属性值,采用...as...group by for..in...
<body> <form name="temp_form" ng-controller = "testController"> <div>学制: <select ng-model = "a" ng-options = "v.id as v.name for v in a_data" ng-change="a_change(a)"> <option value="">--请选择--</option> </select> <span>{{a_show}}</span> </div> <div> 班级: <select ng-model="b" ng-options="v.id as v.name group by v.grade for v in b_data" ng-change="b_change(b)"> <option value="">--请选择--</option> </select> <span>{{b_show}}</span> </div> </form> <div>{{8.8 | number:1 | currency}}</div> <script type="application/javascript"> var con = angular.module('main',[]); con.controller('testController',['$scope',function($scope){ $scope.a_data=[ {id:"1001",name:"小学"}, {id:"1002",name:"初中"}, {id:"1003",name:"大学"} ]; $scope.b_data=[ {id:"1001",name:"(1)班",grade:"一年级"}, {id:"1002",name:"(2)班",grade:"二年级"}, {id:"2001",name:"(1)班",grade:"一年级"}, {id:"2002",name:"(2)班",grade:"二年级"}, {id:"3001",name:"(1)班",grade:"一年级"}, {id:"3002",name:"(2)班",grade:"二年级"} ]; $scope.a = ""; $scope.b = ""; $scope.a_change = function(a){ $scope.a_show = "you selected is " + a; console.info("you selected is " + a); } $scope.b_change = function(b){ $scope.b_show = "you selected is " + b; console.info("you selected is " + b); } }]) </script> </body>
8.过滤器
过滤器的主要功能是格式化数据,这里所说的数据包括视图模板中的表达式,也包括控制器中的数组和对象.
过滤器的三种调用方式:
1.单个过滤器
{{}}双括号为表达式标记,在括号中 | 为管道符,通过该符号分为前后两部分,前部分为表达式,后部分为过滤器名称
<div>{{8.8 | number:1 | currency}}</div>
number过滤器要放在currency过滤器前边,原因大家懂得
2.多个过滤器
{{表达式 | 过滤器1 | 过滤器2 | ...}}
3.带参数的过滤器
{{表达式 | 过滤器1 :参数1 : 参数2}}
currency:货币过滤器
number:四舍五入小数点个数过滤器
排序方式过滤:
$scope.data = [
{name:"张晓明",sex:"男",age:"24",score:95}
]
<li ng-repeat="stu in data | orderBy:'-score' | limitTo:3" ng-class-odd="'odd'" ng-class-even="'even'"></li>
匹配方式过滤:
{{数据 | filter:'匹配字符'}},一旦添加该参数,将在整个数据的属性中查找匹配项,找到后则显示,找不到则不显示,字符内容必须加引号
{{data | filter:80}},在data数据的各个属性中查找包含"80"内容的记录
在字符参数中使用对象形式匹配指定属性的数据:
如果在过滤数据时已经确定了数据匹配的属性范围,可以在字符参数中通过对象的形式指定匹配的属性名称,如下
{{数据 | filter:对象}}
上述调用格式的对象中,过滤器参数是一个对象,这个对象通过key/value方式声明属性名称和匹配的字符内容,如果属性名称为$,则表示在全部的属性中查找,如下
{{data | filter:{score:80}}} {{data | filter:{$:80}}}
后者相当于{{data | filter:80}}
在字符参数中使用自定义函数匹配相应数据:
{{数据 | filter:函数名称}}
参数默认传递循环过程中的当前元素
<div> <ul> <li> <span>序号</span> <span>姓名</span> <span>性别</span> <span>年龄</span> <span>分数</span> </li> <li ng-repeat="stu in data | filter:findscore" ng-class-odd="'odd'" ng-class-even="'even'"> <span>{{$index + 1}}</span> <span>{{stu.name}}</span> <span>{{stu.sex}}</span> <span>{{stu.age}}</span> <span>{{stu.score}}</span> </li> </ul> </div> var con = angular.module('main',[]); con.controller('testController',['$scope',function($scope){ $scope.a_data=[ {id:"1001",name:"小学"}, {id:"1002",name:"初中"}, {id:"1003",name:"大学"} ]; $scope.b_data=[ {id:"1001",name:"(1)班",grade:"一年级"}, {id:"1002",name:"(2)班",grade:"二年级"}, {id:"2001",name:"(1)班",grade:"一年级"}, {id:"2002",name:"(2)班",grade:"二年级"}, {id:"3001",name:"(1)班",grade:"一年级"}, {id:"3002",name:"(2)班",grade:"二年级"} ]; $scope.data = [ {name:"张晓明",sex:"男",age:"24",score:95}, {name:"李晓东",sex:"女",age:"25",score:80}, {name:"马晓华",sex:"男",age:"30",score:85}, {name:"师小婕",sex:"女",age:"23",score:100} ]; $scope.findscore = function (e){ return e.score >80 && e.score < 100; }
自定义过滤器:
在页面模块中注册一个过滤器的构造方法,改方法将返回一个以输入值为首个参数的函数,在函数体中实现过滤器功能.而输入值为默认的被传入过滤器的对象.
<ul> <li> <span>序号</span> <span>姓名</span> <span>性别</span> <span>年龄</span> <span>分数</span> </li> <li ng-repeat="stu in data | young:0" ng-class-odd="'odd'" ng-class-even="'even'"> <span>{{$index + 1}}</span> <span>{{stu.name}}</span> <span>{{stu.sex}}</span> <span>{{stu.age}}</span> <span>{{stu.score}}</span> </li> </ul> con.filter('young',function(){ return function(e,type){ var _out = []; var _sex = type ? "男" : "女"; for(var i = 0; i < e.length; i++){ if(e[i].age > 22 && e[i].age < 30 && e[i].sex == _sex){ _out.push(e[i]); } } return _out; } })
过滤器默认传入参数e,代表当前元素.在自定义过滤器中,当前元素代表整个集合对象,在自定义函数过滤器中当前元素为整个结合对象中的当前循环元素.
返回以输入值(被过滤值)为首个参数的函数,通过return返回一个函数,参数e为在调用过滤器时,会被过滤的数据自动注入的,其他参数为过滤器传入的自定义参数,通过冒号向过滤器传递,先定义返回值,在做逻辑处理.
表头排序:
<ul> <li> <span>序号</span> <span ng-click="title='name';desc = !desc">姓名</span> <span ng-click="title='sex';desc = !desc">性别</span> <span ng-click="title='age';desc = !desc">年龄</span> <span ng-click="title='score';desc = !desc">分数</span> </li> <li ng-repeat="stu in data | orderBy:title:desc" ng-class-odd="'odd'" ng-class-even="'even'"> <span>{{$index + 1}}</span> <span>{{stu.name}}</span> <span>{{stu.sex}}</span> <span>{{stu.age}}</span> <span>{{stu.score}}</span> </li> </ul> </div> con.controller('testController',['$scope',function($scope){ $scope.desc = 0; $scope.title = "name";
确定controller作用域后,controller为变量初始化,这个时候变量已经被赋值,函数变量会被初始化,但是不会执行函数.
orderBy过滤器带有两个参数,第一个参数指定排序的属性名,第二个参数指定排序的方向,该值默认或缺省时为升序,1为降序,0为升序.
字符查找:
<li ng-repeat="stu in data | filter : {name:key}" ng-class-odd="'odd'" ng-class-even="'even'"> $scope.key = ' '; {name:"师小婕 ",sex:"女",age:"23",score:100}
name引号可有可无.
9.作用域:
作用域能存储数据模型,为表达式提供上下文环境和监听表达式变化并传播事件,它是页面视图和控制器之间的重要桥梁.
提供了$watch方法来监听数据模型的变化,ng-model实现双向数据绑定就是通过该方法进行数据模型的监听.
提供了$apply方法为各种类型的数据模型改变提供支撑,例如通过视图模板中的ng-click来执行控制器中的代码.
提供了执行环境,一个表达式必须在拥有该表达式属性的作用域中执行,作用域通过提供$scope对象,使所有的表达式对象都拥有执行环境.
$watch:
<div> <div> <input type="text" ng-model = "name" placeholder="please input you name" /> </div> <div>累计变化次数:{{count}}</div> </div> $scope.count = 0; $scope.name = ''; $scope.$watch('name',function(){ $scope.count ++; })
需要注意的是第一次加载时初始化过程中也是认为该值是改变的undefined--初始化,该方法也会执行.
作为数据模型的作用域:
作用域是控制器和视图的桥梁,同时作用域也是指令和视图的桥梁,无论是指令,还是控制器他们都可以通过作用域与视图中的DOM进行绑定.两条数据关系链
指令->作用域->视图 控制器->作用域->视图
作用域的层级和事件:
子级作用域可以继承父级作用域中的全部属性和方法,同级别子作用域不可以相互访问各自的属性和方法.
引入作用域
con.controller('testController',['$scope',function($scope){
作用域事件传播:
两种方式可以实现作用域间的通信
服务(service):
事件(event):
Angular中提供的两个方法:$broadcasted,$emitted
$broadcasted:将事件从父级作用域传播到子级作用域
$broadcasted(eventname,data) data为事件传播过程中携带的数据信息.
$emitted:将事件从子级作用域传播到父级作用域
$emitted(eventname,data)
除了这两个传播事件的方法外,还需要调用$on方法,在作用域中监控传播来的事件,并获取相应的数据.$on(eventname,function(event,data){接收传播事件的处理方法})
在一个作用域中定义事件的传播,然后在其他作用域中通过$on方法监控事件传播的状态.
不同controller的作用域不同,通过调用作用域中的函数,并定义事件的传播,在其他的作用域中监听事件传播. controller1 $scope.to_patient = function(){ $scope.$emit('event_1',"事件来源于子级") } $scope.to_child = function(){ $scope.$broadcast('event_2',"事件来源于父级") } controller2 $scope.$on('event_1',function(event,data){ ... })
在监听函数中通过event下边相关方法操作被监听的域中的相关操作
10.依赖注入:
依赖注入原理:
var myApp = angular.module('myapp',[]); myApp.controller('ctl',['$scope',function($scope){ }]) myApp.config(function($controllerProvider){ $controllerProvider.register('ctl',['$scope'.Function($scope){ }]) })
第一段代码为常用代码,第一段代码在Angular中执行的本质其实是第二段代码.
11.angular中mvc模式:
模板跳转:
<a href="#view/{{stu.stuId}}>{{stu.stuName}}</a> $routeProvider.when('/view/:id',{ controller:'ctl', templateUrl:'aa.html', publicAccess:true }) myApp.controller('ctl',function($scope,$routeParams){ for(var i = 0;i<students.length;i++){ if(students[i].stuId == $routeParams.id){ $scope.student = students[i]; } } })
12. Angular 的服务
在Angular中服务是一种单利对象,服务的主要功能是为实现应用的功能提供数据和对象.按照功能不同,分为内置和自定义的服务.
内置服务如:$scope,$http,$windows,$location
$location:
获取当前地址栏中完整的url地址.
myApp.controller('ctl1',function($scope,$location){ $scope.clicked = function(){ $scope.url = $location.absUrl(); } })
自定义服务:
只需将服务注入到需要服务的容器中(控制器,指令,或其他自定义服务)就可以采用对象的方式调用服务中的属性和方法
定义服务的方法主要包含两种,一种是使用内置的$provider服务,一种是调用模块中的服务注册方法,如factory,service,constant,value等方法
添加自定义服务依赖选项方法:
隐式声明:指的是在创建服务的函数中,直接在参数中调用,不进行任何声明,如果对代码进行压缩时,注入的对象可能失效
app.factory('serviceName',function(dep1,dep2){});
调用$inject属性:将需要注入服务的各种对象包装成一个数组,并将它们作为$inject属性值,但是执行效率很低,不推荐
sf表示服务执行的函数
var sf = functioin(dep1,dep2){}; sf.$inject = ['dep1','dep2']; app.factory('ServiceName',sf);
显示声明:指的是在创建服务的函数中,添加一个数组,在数组中顺序声明需要注入的服务或对象名称,高效,不丢代码,推荐使用,参数中的名称和声明可以不一样但是顺序必须一样
app.factory('serviceName',['dep1','dep2',function(dep1,dep2){}]);
&& 通过指令在ng-repeat中动态添加删除class
<li ng-repeat="stu in data | filter : {name:key}" ng-class-odd="'odd'" ng-class-even="'even'"> <span repeat-my >{{$index + 1}}</span> <span repeat-my>{{stu.name}}</span> <span repeat-my>{{stu.sex}}</span> <span repeat-my>{{stu.age}}</span> <span repeat-my>{{stu.score}}</span> </li> con.directive("repeatMy",function(){ return { restrict:"A", link:function(scope,elem,attrs){ elem.bind('click',function(){ var test = attrs.$$element[0]; console.info(test.getAttribute('class').indexOf('ok')) if(test.getAttribute('class').indexOf('ok') > 0){ elem.removeClass("ok"); }else{ elem.addClass("ok"); } }) } } })
13. $apply Scope提供$apply方法传播Model的变化
什么时候使用$apply()方法呢?情况非常少,实际上几乎我们所有的代码都包在scope.apply()里面,像ng−click,controller的初始化,http的回调函数等。在这些情况下,我们不需要自己调用,实际上我们也不能自己调用,否则在apply()方法里面再调用apply()方法会抛出错误。如果我们需要在一个新的执行序列中运行代码时才真正需要用到它,而且当且仅当这个新的执行序列不是被angular JS的库的方法创建的,这个时候我们需要将代码用scope.apply()包起来。下面用一个例子解释: <div ng:app ng-controller="Ctrl">{{message}}</div> functionCtrl($scope) { $scope.message ="Waiting 2000ms for update"; setTimeout(function () { $scope.message ="Timeout called!"; // AngularJS unaware of update to $scope }, 2000); } 上面的代码执行后页面上会显示:Waiting 2000ms for update。显然数据的更新没有被angular JS觉察到。 接下来,我们将Javascript的代码稍作修改,用scope.apply()包起来。 functionCtrl($scope) { $scope.message ="Waiting 2000ms for update"; setTimeout(function () { $scope.$apply(function () { $scope.message ="Timeout called!"; }); }, 2000); } 这次与之前不同的是,页面上先会显示:Waiting 2000ms for update,等待2秒后内容会被更改为:Timeout called! 。显然数据的更新被angular JS觉察到了。 NOTE:我们不应该这样做,而是用angular JS提供的timeout方法,这样它就会被自动用apply方法包起来了。 科学是把双刃剑 最后,我们再来瞅一眼scope.apply()和scope.apply(function)方法吧!虽然angular JS为我们做了很多事情,但是我们也因此丢失了一些机会。从下面的伪代码一看便知: function$apply(expr) { try { return$eval(expr); } catch(e) { $exceptionHandler(e); } finally { $root.$digest(); } } 它会捕获所有的异常并且不会再抛出来,最后都会调用$digest()方法。 总结一下 $apply()方法可以在angular框架之外执行angular JS的表达式,例如:DOM事件、setTimeout、XHR或其他第三方的库。这仅仅是个开始,水还有很深,欢迎大家一起来deep dive!
14.scope.$watch
$watch(watchFn,watchAction,deepWatch)
watchFn:angular表达式或函数的字符串
watchAction(newValue,oldValue,scope):watchFn发生变化会被调用
deepWatch:可选的布尔值命令检查被监控的对象的每个属性是否发生变化
$watch会返回一个函数,想要注销这个watch可以使用函数
scope.$watch( function () { return scope.$eval(attrs.bfAssertSameAs); }, function () { ngModel.$setValidity('same', isSame(ngModel.$modelValue)); } );
var firstController = function ($scope){ $scope.name='张三'; $scope.count=0; // 监听一个model 当一个model每次改变时 都会触发第2个函数 $scope.$watch('name',function(newValue,oldValue){ ++$scope.count; if($scope.count > 30){ $scope.name = '已经大于30次了'; } }); }
15.通过指令获取元素的值,以及作用域中的其他值
16.页面追加元素
angular.module("com.ngnice.app").directive('bfFieldError', function bfFieldError($compile){ return { restrict: 'A', require: 'ngModel', link: function(scope, element, attrs, ngModel){ var subScope = scope.$new(true); subScope.hasError = function(){ return ngModel.$invalid && ngModel.$dirty; }; subScope.errors = function(){ return ngModel.$error; }; var hint = $compile('<ul class="" ng-if="hasError()"><li ng-repeat="(name,wrong) in errors()" ng-if="wrong">{{name | error}}</li></ul>')(subScope); element.after(hint); } }; });
17. 删除数组元素
$scope.array.splice($.inArray(id, $scope.array), 1);
18. 按钮变换,焦点获取
<tbody> <tr ng-repeat="cor in cors"> <td>{{$index + 1}}</td> <td>{{cor.mistake}}</td> <td style="padding: 0px 0px;"> <input type="text" name="correction" class="form-control" ng-model="cor.correction" readonly/> </td> <td>{{cor.operator}}</td> <td>{{cor.updatetime | date:'yyyy-MM-dd hh:mm:ss'}}</td> <td> <a href="javascript:void(0)" class="operate_a" ng-click="editSec($event,cor.id,cor.correction)">编辑</a> <a href="javascript:void(0)" class="operate_a" ng-click="deleteCor(cor.id)">删除</a> </td> </tr> </tbody>
$scope.editSec = function (event,id,context) { if(angular.element(event.target).context.innerHTML == "编辑"){ angular.element(event.target).parents("tbody").find("input").attr("readonly","readonly"); angular.forEach(angular.element(event.target).parents("tbody").find("input"),function (data, index, array) { angular.element(angular.element(data).parents("tr").find("a")[0]).context.innerHTML = "编辑"; }) $scope.checkEdit = false; angular.element(event.target).parents("tr").find("input").removeAttr('readonly').focus(); angular.element(event.target).context.innerHTML = "保存"; }else{ $scope.updateCor(id,context); $scope.checkEdit = true; angular.element(event.target).parents("tr").find("input").attr("readonly","readonly"); angular.element(event.target).context.innerHTML = "编辑"; } }