@octopus
2016-09-14T10:26:10.000000Z
字数 16460
阅读 1638
angular.js
- 此笔记为观看油管大神 @kudvenkat 视频的学习中所做笔记 YouTube视频链接
- 同时借鉴《AngularJS权威教程》一书整理相关概念
官方定义:
一个应用可以包含多个模块,每一个模块都包含了定义具体功能的代码。
我们使用 angular.module()方法来声明模块,这个方法能够接受两个参数,第一个是模块的名称,第二个是依赖列表,也就是可以被注入到模块中的对象列表。
简而言之:
- 模块就是为了不污染全局空间自定义的作用域,在作用域内控制器的一系列操作才会生效。
<html ng-app="myApp"> // 在html代码中定义模块的作用范围...</html><script>var myapp = angular.module('myApp', []); // 声明模块</script>
官方:
- 控制器是一个函数,用来向视图的作用域中添加额外的功能。我们用它来给作用域对象设置初始状态,并添加自定义行为。
简而言之:
- 控制器可以定义作用域对象,定义方法,来为前台提供有效数据、响应事件。
<div ng-controller="FirstController">...</div><script>var app = angular.module('app', []);app.controller('FirstController', function($scope) {$scope.message = "hello";});</script>
官方:
$scope对象是定义应用业务逻辑、控制器方法和视图属性的地方。作用域是视图和控制器之间的胶水。
作用域是应用状态的基础。基于动态绑定,我们可以依赖视图在修改数据时立刻更新 $scope,也可以依赖 $scope在其发生变化时立刻重新渲染视图,有监视数据模型变化的能力。
当需要动态绑定src路径时,一定要用 ng-src 指令,用原始 src 浏览器加载时会把ng的变量名当做路径先加载,导致一个资源未找到的错误,然后ng再解析包含路径对应的资源。
<img src="{{src}}" alt="Description" /> // bug<img ng-src="{{src}}" alt="Description" /> // 正确<script>var app = angular.module('app', []);app.controller('xxController', function($scope) {$scope.src = "www.baidu.com";});</script>
<div ng-controller="myController"><table><tr><th>number</th><th>name</th><th>age</th><th>city</th></tr><tr ng-repeat="employee in employees"><td>{{ $index }}</td><td>{{ employee.name }}</td><td>{{ employee.age }}</td><td>{{ employee.city }}</td></tr></table></div><script>var myapp = angular.module("myApp", [])myapp.controller("myController", function($scope) {var employees = [{name:"zhang",age:18,city:"shandong"},{name:"lisi",age:20,city:"jinan"},{name:"wangwu",age:27,city:"shanghai"},];$scope.employees = employees;});</script>
其中,
$index与$parent.$index可以获取当前迭代号与父节点的迭代号

ng-hide=true 隐藏
ng-hide=false 显示
<div ng-controller="myController">· hide? <input type="checkbox" ng-model="hideSalary" /> // 页面初次载入时此并未定义,undefind,所以等同于false<table class="table table-bordered"><tr class="danger"><th>name</th><th>city</th><th ng-hide="hideSalary">salary</th></tr><tr ng-repeat="people in peoples"><td>{{ people.name }}</td><td>{{ people.city }}</td><td ng-hide="hideSalary">{{ people.salary }}</td></tr></table></div><script>angular.module("myApp", []).controller("myController", function($scope) {var peoples = [{name:"zhangyu",city:"jinan",salary:55000},{name:"wangwu",city:"beijing",salary:35600},{name:"lisi",city:"shanghai",salary:2100},{name:"wanger",city:"shenzhen",salary:61000}];$scope.peoples = peoples;});</script>

ng-show=true 显示
ng-show=false 隐藏
ng-init 定义作用域的属性,但尽可能的把控制器能做的交给控制器去做
<ul><li ng-repeat="people in peoples" ng-init="parentIndex = $index">{{$index}}<ul><li ng-repeat="thing in people.something">{{parentIndex}}</li></ul></li></ul>
包含其他 HTML 文件,但经测试只在有 firfox 有效,chrome 无效
<div ng-controller="myController"><select ng-model="selectPage"><option value="index2.html">index2.html</option><option value="index3.html">index3.html</option></select><div ng-include="selectPage"></div></div><script>angular.module("myApp", []).controller("myController", function($scope) {$scope.selectPage = "index2.html";});</script>

<div ng-controller="myController"><table><tr><th>technolog</th><th>like</th><th>dislike</th><th>like/dislike btn</th></tr><tr ng-repeat="technolog in technologies"><td>{{ technolog.name }}</td><td>{{ technolog.likes }}</td><td>{{ technolog.dislikes }}</td><td><input type="button" value="like" ng-click="likes(technolog)"><input type="button" value="dislike" ng-click="dislikes(technolog)"></td></tr></table></div><script>angular.module("myApp", []).controller("myController", function($scope) {var technologies = [{name:"php",likes:0,dislikes:0},{name:"java",likes:0,dislikes:0},{name:"c#",likes:0,dislikes:0},{name:"c++",likes:0,dislikes:0},{name:"angularjs",likes:0,dislikes:0}];$scope.technologies = technologies;$scope.likes = function(technologies){technologies.likes++;};$scope.dislikes = function(technologies){technologies.dislikes++;};});</script>

filter 有三种作用:1. 格式化 2. 排序 3. 过滤
基本格式:{{ expression | filterName:parameter }}
{{ "ZHANG" | lowercase }} // zhang
{{ "zhang" | uppercase }} // ZHANG
{{ 5320000.225 | number:2 }} // 5,320,000.22 (保留两位小数)
{{ date | date:"dd-MM-yyyy" }} // 08-09-2016 ( $scope.date = new Date(); )
格式:
{{ expression | orderBy:"+age" }}表示对age升序排序,同理 "-age" 表示降序排序,默认为升序
<div ng-controller="myController">order by:<select ng-model="sort"> // *<option value="+name">name - ASC</option><option value="+salary">salary - ASC</option><option value="-name">name - DESC</option><option value="-salary">salary - DESC</option></select><table class="table table-bordered"><tr class="danger"><th>name</th><th>salary</th></tr><tr ng-repeat="people in peoples | orderBy:sort"><td>{{ people.name }}</td><td>{{ people.salary }}</td></tr></table></div><script>angular.module("myApp", []).controller("myController", function($scope) {var peoples = [{name:"zhangyu",salary:55000},{name:"wangyu",salary:35600},{name:"lisi",salary:2100},{name:"wanger",salary:61000}];$scope.peoples = peoples;$scope.sort = "name"; // *});</script>

充分利用动态数据绑定,更新排序字段与排序方式
<div ng-controller="myController"><table class="table table-bordered"><tr class="danger"><th ng-click="sortData('name')">name <div ng-class="getSortClass('name')"></div></th><th ng-click="sortData('salary')">salary <div ng-class="getSortClass('salary')"></div></th></tr><tr ng-repeat="people in peoples | orderBy:sort:reverseSort"> // * reverseSort 为 true 则正序排序,false 为倒序排序<td>{{ people.name }}</td><td>{{ people.salary }}</td></tr></table></div><script>angular.module("myApp", []).controller("myController", function($scope) {var peoples = [{name:"zhangyu",salary:55000},{name:"wangyu",salary:35600},{name:"lisi",salary:2100},{name:"wanger",salary:61000}];$scope.peoples = peoples;$scope.sort = "name";$scope.reverseSort = false;$scope.sortData = function(column){$scope.reverseSort = ($scope.sort == column)? !$scope.reverseSort : false;$scope.sort = column;};$scope.getSortClass = function(column){if ($scope.sort == column){return $scope.reverseSort ? 'arrow-down':'arrow-up';}return '';};});</script>
// css 样式.arrow-up{width:0;height: 0;border-left: 5px solid transparent;border-right: 5px solid transparent;border-bottom: 5px solid black;float: right;margin-top: 8px;}.arrow-down{width:0;height: 0;border-left: 5px solid transparent;border-right: 5px solid transparent;border-top: 5px solid black;float: right;margin-top: 8px;}

<div ng-controller="myController">显示行数:<input type="number" ng-model="limit" /> // *<br><br><table class="table table-bordered"><tr class="danger"><th>technolog</th><th>like</th><th>dislike</th><th>like/dislike btn</th></tr><tr ng-repeat="technolog in technologies | limitTo:limit"> // *<td>{{ technolog.name }}</td><td>{{ technolog.likes }}</td><td>{{ technolog.dislikes }}</td><td><input type="button" value="like" ng-click="likes(technolog)"><input type="button" value="dislike" ng-click="dislikes(technolog)"></td></tr></table></div><script>angular.module("myApp", []).controller("myController", function($scope) {var technologies = [{name:"php",likes:0,dislikes:0},{name:"java",likes:0,dislikes:0},{name:"c#",likes:0,dislikes:0},{name:"c++",likes:0,dislikes:0},{name:"angularjs",likes:0,dislikes:0}];$scope.technologies = technologies;$scope.likes = function(technologies){technologies.likes++;};$scope.dislikes = function(technologies){technologies.dislikes++;};$scope.limit = 3; // *});</script>

卧槽超级简单啊,相关代码只有两句话!关键语句:<tr ng-repeat="people in peoples | filter:filterName">
<div ng-controller="myController">Search: <input type="text" ng-model="searchText"> // *<table class="table table-bordered"><tr class="danger"><th>name</th><th>salary</th></tr><tr ng-repeat="people in peoples | filter:searchText"> // *<td>{{ people.name }}</td><td>{{ people.salary }}</td></tr></table></div><script>angular.module("myApp", []).controller("myController", function($scope) {var peoples = [{name:"zhangyu",salary:55000},{name:"wangwu",salary:35600},{name:"lisi",salary:2100},{name:"wanger",salary:61000}];$scope.peoples = peoples;});</script>

<div ng-controller="myController">Search name: <input type="text" ng-model="searchText.name">Search city: <input type="text" ng-model="searchText.salary">精确查找:<input type="checkbox" ng-model="exactMatch"><table class="table table-bordered"><tr class="danger"><th>name</th><th>salary</th></tr><tr ng-repeat="people in peoples | filter:searchText:exactMatch"> // * 精确查找<td>{{ people.name }}</td><td>{{ people.salary }}</td></tr></table></div><script>angular.module("myApp", []).controller("myController", function($scope) {var peoples = [{name:"zhangyu",salary:55000},{name:"wangwu",salary:35600},{name:"lisi",salary:2100},{name:"wanger",salary:61000}];$scope.peoples = peoples;});</script>

// 在同一搜索框过滤 name、city 两属性<div ng-controller="myController">Search name&city: <input type="text" ng-model="searchText"> <br><table class="table table-bordered"><tr class="danger"><th>name</th><th>city</th><th>salary</th></tr><tr ng-repeat="people in peoples | filter:search"><td>{{ people.name }}</td><td>{{ people.city }}</td><td>{{ people.salary }}</td></tr></table></div><script>angular.module("myApp", []).controller("myController", function($scope) {var peoples = [{name:"zhangyu",city:"jinan",salary:55000},{name:"wangwu",city:"beijing",salary:35600},{name:"lisi",city:"shanghai",salary:2100},{name:"wanger",city:"shenzhen",salary:61000}];$scope.peoples = peoples;$scope.search = function(item){ // 把表格传进来if($scope.searchText == undefined ||item.name.toLowerCase().indexOf($scope.searchText.toLowerCase()) != -1 ||item.city.toLowerCase().indexOf($scope.searchText.toLowerCase()) != -1){return true; // 有符合条件的就返回}return false;};});</script>

关键:在
angular的.filter()方法中返回自定义函数,本例把城市编号转换成对应的城市名
<div ng-controller="myController"><table class="table table-bordered"><tr class="danger"><th>name</th><th>city</th><th>salary</th></tr><tr ng-repeat="people in peoples | filter:search"><td>{{ people.name }}</td><td>{{ people.cityNum |city }}</td> // 过滤器的名字<td>{{ people.salary }}</td></tr></table></div><script>angular.module("myApp", []).filter("city",function(){ // 定义过滤器return function (cityNum) { // 返回自定义过滤器的实现switch (cityNum){case 1:return "beijing";case 2:return "shanghai";case 3:return "shenzhen";}}}).controller("myController", function($scope) {var peoples = [{name:"zhangyu",cityNum:1,salary:55000},{name:"wangwu",cityNum:2,salary:35600},{name:"lisi",cityNum:1,salary:2100},{name:"wanger",cityNum:3,salary:61000}];$scope.peoples = peoples;});</script>

$http({method: 'GET',url: '/someUrl'}).then(function successCallback(response) {...}, function errorCallback(response) {...});
实例:
<div ng-controller="myController">{{data}}{{error}}</div><script>angular.module("myApp", []).controller("myController", function($scope, $http, $log) {$http({method:'GET',url:'a.php'}).then(function(response){$scope.data = response.data;},function(response){$scope.error = response.data;});});</script>// a.phpecho json_encode("ok!");
这种写法并不简单易读,所以我们应该把 成功&失败 的回调函数提取出来
<script>angular.module("myApp", []).controller("myController", function($scope, $http, $log) {var successCallBack = function(response){$scope.data = response.data;$log.log(response);};var errCallBack = function(response){$scope.error = response.data;$log.log(response);};$http({method:'GET',url:'a.php'}).then(successCallBack,errCallBack);});</script>
在控制台打印不同类型的日志信息
log();
info();
warn();
error();
debug();

<div ng-controller="myController">{{data.name}}</div><script>angular.module("myApp", []).controller("myController", function($scope, $http, $log) {$http({method:'GET',url:'a.php'}).then(function(res){$scope.data = res.data;$log.log(res); // *});});</script>
$location 服务提供了一些访问与操作URL的方法。
hash() 在url的尾部添加 "#xxx",详细实例见\$anchorScroll
$anchorScroll() 去当前url指定位置,通常与$location.hash连用,实现锚点
<div ng-controller="myController"><button id="top" ng-click="scrollTo('bottom')">go to the bottom</button><div class="pad"><p>hello world!</p><p>hello world!</p>...<p>hello world!</p></div><button id="bottom" ng-click="scrollTo('top')">go to the top</button></div><script>var myapp = angular.module("myApp", []).controller("myController", function($scope,$location,$anchorScroll) {$scope.scrollTo = function (ScrollLocation) {$location.hash(ScrollLocation);$anchorScroll();}});</script>

$q服务是AngularJS中自己封装实现的一种Promise实现, promise解决的是异步编程的问题。假设有一个家具厂,而它有一个VIP客户张先生。有一天张先生需要一个豪华衣柜,于是,他打电话给家具厂说我需要一个衣柜,回头做好了给我送来, 这个操作就叫$q.defer,也就是延期,因为这个衣柜不是现在要的,所以张先生这是在发起一个可延期的请求。同时,家具厂给他留下了一个回执号,并对他说:我们做好了会给您送过去,放心吧。这叫做promise,也就是承诺。这样,这个defer算是正式创建了,于是他把这件事记录在自己的日记上,并且同时记录了回执号,这叫做deferred,也就是已延期事件。现在,张先生就不用再去想着这件事了,该做什么做什么,这就是“异步”的含义。假设家具厂在一周后做完了这个衣柜,并如约送到了张先生家(包邮哦,亲),这就叫做deferred.resolve(衣柜),也就是“已解决”。而这时候张先生只要签收一下这个(衣柜)参数就行了,当然,这个“邮包”中也不一定只有衣柜,还可以包含别的东西,比如厂家宣传资料、产品名录等。整个过程中轻松愉快,谁也没等谁,没有浪费任何时间。假设家具厂在评估后发现这个规格的衣柜我们做不了,那么它就需要deferred.reject(理由),也就是“拒绝”。拒绝没有时间限制,可以发生在给出承诺之后的任何时候,甚至可能发生在快做完的时候。而且拒绝时候的参数也不仅仅限于理由,还可以包含一个道歉信,违约金之类的,总之,你想给他什么就给他什么,如果你觉得不会惹恼客户,那么不给也没关系。假设家具厂发现,自己正好有一个符合张先生要求的存货,它就可以用$q.when(现有衣柜)来把这个承诺给张先生,这件事就立即被解决了,皆大欢喜,张先生可不在乎你是从头做的还是现有的成品,只会惊叹于你们的效率之高。假设这个家具厂对客户格外的细心,它还可能通过deferred.notify(进展情况)给张先生发送进展情况的“通知”。这样,整个异步流程就圆满完成,无论成功或者失败,张先生都没有往里面投入任何额外的时间成本。好,我们再扩展一下这个故事:张先生这次需要做一个桌子,三把椅子,一张席梦思,但是他不希望今天收到个桌子,明天收到个椅子,后天又得签收一次席梦思,而是希望家具厂做好了之后一次性送过来,但是他下单的时候又是分别下单的,那么他就可以重新跟家具厂要一个包含上述三个承诺的新承诺,这就是$q.all(桌子承诺,椅子承诺,席梦思承诺),这样,他就不用再关注以前的三个承诺了,直接等待这个新的承诺完成,到时候只要一次性签收了前面的这些承诺就行了。———— 摘自大神 @雪狼
再来看一下程序版本的讲解:
1、$q是Angular的一种内置服务,它可以使你异步地执行函数,并且当函数执行完成时它允许你使用函数的返回值(或异常)。
2、defer的字面意思是延迟, $q.defer() 可以创建一个deferred实例(延迟对象实例)。deferred 实例旨在暴露派生的Promise实例,以及被用来作为成功完成或未成功完成的信号API,以及当前任务的状态。这听起来好复杂的样子,总结$q, defer, promise三者之间的关系如下所示。
var deferred = $q.defer(); //通过$q服务注册一个延迟对象 deferredvar promise = deferred.promise; //通过deferred延迟对象,可以得到一个承诺promise,而promise会返回当前任务的完成结果defer的方法:1. deferred.resolve(value) 成功解决(resolve)了其派生的promise。参数value将来会被用作promise.then(successCallback(value){...}, errorCallback(reason){...}, notifyCallback(notify){...})中successCallback函数的参数。2. deferred.reject(reason) 未成功解决其派生的promise。参数reason被用来说明未成功的原因。此时deferred实例的promise对象将会捕获一个任务未成功执行的错误,promise.catch(errorCallback(reason){...})。补充一点,promise.catch(errorCallback)实际上就是promise.then(null, errorCallback)的简写。3. notify(value) 更新promise的执行状态(翻译的不好,原话是provides updates on the status of the promise's execution)
栗子:
function asyncGreet(name) {var deferred = $q.defer(); //通过$q.defer()创建一个deferred延迟对象,在创建一个deferred实例时,也会创建出来一个派生的promise对象,使用deferred.promise就可以检索到派生的promise。deferred.notify('About to greet ' + name + '.'); //延迟对象的notify方法。if (okToGreet(name)) {deferred.resolve('Hello, ' + name + '!'); //任务被成功执行} else {deferred.reject('Greeting ' + name + ' is not allowed.'); //任务未被成功执行}return deferred.promise; //返回deferred实例的promise对象}function okToGreet(name) { //只是mock数据,实际情况将根据相关业务实现代码if(name == 'Superman') return true;else return false;}var promise = asyncGreet('Superman'); //获得promise对象//promise对象的then函数会获得当前任务也就是当前deferred延迟实例的执行状态。它的三个回调函数分别会在resolve(), reject() 和notify()时被执行promise.then(function(greeting) {alert('Success: ' + greeting);}, function(reason) {alert('Failed: ' + reason);}, function(update) {alert('Got notification: ' + update);});
var Todo = $resource('/api/1/todo/:id');//create a todovar todo1 = new Todo();todo1.foo = 'bar';todo1.something = 123;todo1.$save();//get and update a todovar todo2 = Todo.get({id: 123});todo2.foo += '!';todo2.$save();//which is basically the same as...Todo.get({id: 123}, function(todo) {todo.foo += '!';todo.$save();});//get a list of todosTodo.query(function(todos) {//do something with todosangular.forEach(todos, function(todo) {todo.foo += ' something';todo.$save();});});//delete a todoTodo.$delete({id: 123});
// index.html<div ng-controller="myController"><table class="table"><tr><th>Input String</th><td><input type="text" ng-model="input"></td></tr><tr><th>Result</th><td><input type="text" ng-model="output"></td></tr></table><button class="btn btn-primary" ng-click="go(input)">go!</button></div><script src="angular-1.5.8/angular.min.js"></script><script src="js/indexController.js"></script><script src="js/stringService.js"></script>// indexController.jsvar myapp = angular.module("myApp", []).controller("myController", function($scope,stringService) { // 注入服务$scope.go = function(input){$scope.output = stringService.processString(input); // 调用服务的方法};});// stringService.jsmyapp.factory('stringService',function(){return { // 需要返回一个对象processString: function (input) { // 服务的方法(方法名:函数)if(!input){return input;}var output = "";for(var i = 0; i<input.length;i++){if(i > 0 && input[i] == input[i].toUpperCase()){output = output + " ";}output = output + input[i];}return output;}}});
