AngularJS 笔记
使用angularjs已经有一年多的时间,在这期间遇到过不少的问题,但却都没有记录下来,以至于很多时候都得反复去查找相同的资料,所以现在打算从此刻开始积累记录。
fromJson 和 toJson 方法
angular.fromJson()方法是把json转化为对象或者对象数组,源码如下:
function fromJson(json) {
return isString(json) ? JSON.parse(json) : json
}
angular.toJson()方法是把对象或者数组转化json,源码如下:
function toJson(obj, pretty) {
return "undefined" == typeof obj ? undefined : JSON.stringify(obj, toJsonReplacer, pretty ? " " : null)
}
promise
angular的promise是由$q提供和构件的,$q提供了一个通过注册一个promise项目来异步执行的方法。
JS中处理异步回调总是非常麻烦,复杂:
// 案例1:在前一个动画执行完成后,紧接着执行下一个动画
$('xx').animate({xxxx}, function(){
$('xx').animate({xx},function(){
//do something
},1000)
},1000)
// 案例2:jquery ajax 异步请求
$.get('url').then(function () {
$.post('url1').then(function () {
//do something
});
});
Promise 有助于开发人员逃离深度嵌套异步回调函数的深渊。Angularjs他通过$q服务提供和构建promise。一个最完整的案例:
var defer1 = $q.defer();
function fun() {
var deferred = $q.defer();
$timeout(function () {
deferred.notify("notify");
if (iWantResolve) {
deferred.resolve("resolved");
} else {
deferred.reject("reject");
}
}, 500);
return deferred.promise;
}
$q.when(fun())
.then(function(success){
console.log("success");
console.log(success);
},function(err){
console.log("error");
console.log(err);
},function(notify){
console.log("notify");
console.log(notify);
})
.catch(function(reson){
console.log("catch");
console.log(reson);
})
.finally(function(final){
console.log('finally');
console.log(final);
});
Promise的调用:$q.when(fun()).then(successCallback, errorCallback, notifyCallback);
简写为:fun().then(successCallback, errorCallback, notifyCallback);
angularjs service封装使用:
angular.module("MyService", [])
.factory('githubService', ["$q", "$http", function($q, $http){
var getPullRequests = function(){
var deferred = $q.defer();
var promise = deferred.promise;
$http.get("url")
.success(function(data){
var result = [];
for(var i = 0; i < data.length; i++){
result.push(data[i].user);
deferred.notify(data[i].user); // 执行状态改变通知
}
deferred.resolve(result); // 成功解决(resolve)了其派生的promise。参数value将来会被用作successCallback(success){}函数的参数value。
})
.error(function(error){
deferred.reject(error); // 未成功解决其派生的promise。参数reason被用来说明未成功的原因。此时deferred实例的promise对象将会捕获一个任务未成功执行的错误,promise.catch(errorCallback(reason){...})。
});
return promise;
}
return {
getPullRequests: getPullRequests
};
}]);
angular.module("MyController", [])
.controller("IndexController", ["$scope", "githubService", function($scope, githubService){
$scope.name = "dreamapple";
$scope.show = true;
githubService.getPullRequests().then(function(result){
$scope.data = result;
},function(error){
},function(progress){
// 执行状态通知 notifyCallback
});
}]);
$http、$httpProvider服务
$http 是angular 封装好的 XMLHttpRequest 请求,angular 的思想偏向restful概念, 方法有:GET,POST,PUT,DELTE,PATCH,HEAD等
angular 默认的请求头:
Accept: application/json, text/plain 接受json和text
Content-Type : application/json
如果要修改默认设置的话可以在app.config上做修改
var app = angular.module("app", []);
app.config(function ($httpProvider) {
log(angular.toJson($httpProvider.defaults));
$httpProvider.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
$httpProvider.defaults.headers.put["Content-Type"] = "application/x-www-form-urlencoded";
$httpProvider.defaults.headers.patch["Content-Type"] = "application/x-www-form-urlencoded";
});
只要是default的headers,在每次发送请求的时候都会带上。所以如果我们每个请求都有用到一些自定义的header,我们也可以写入在default.headers中。$httpProvider.defaults.headers.common["myHeader"] = "myheaderValue";//common 表示不管任何的 method POST,GET,PUT等
这些default的header是可以在每一次我们发请求的时候通过参数来覆盖掉.另外$http service 也提供了一个defaults的指针 (注: $httpProvider.defaults === $http.defaults )
$httpProvider.defaults.transformRequest & transformResponse
这是angular提供给我们的2个接口,在请求发送前和响应还没有触发callback前对post data 和 response data做一些处理它们是个数组类型,我们可以push一些函数进去 (angular默认对request和response都放入了一个方法,post的时候如果data是对象将json化,响应时如果data是json类型,将解析成对象)。在每一次的请求,我们依然可以覆盖整个数组。
var app = angular.module("app", []);
app.config(function ($httpProvider) {
$httpProvider.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
$httpProvider.defaults.transformRequest.shift(); //把angular default的去掉
$httpProvider.defaults.transformRequest.push(function (postData) { //这个function不是依赖注入哦
if (angular.isObject(postData)) {
return $.param(postData); //如果postData是对象就把它转成param string 返回, 这里借用了jQuery方法
}
return postData;
});
$httpProvider.defaults.transformResponse.push(function (responseData) {
log(angular.toJson(responseData)); //响应的数据可以做一些处理
return "data";
});
});
app.controller("ctrl", function ($scope, $http) {
$http({
method: "POST",
url: "handle.ashx",
data: {
key: "value"
},
transformResponse: [], //每一次请求也可以覆盖default
transformResponse: $http.defaults.transformResponse.concat([function () { return "abc" }]) //如果default要保留要concat
}).success(function (responseData) {
log(responseData === "abc"); //true
});
});
$httpProvider.defaults.cache。angular 默认cahce = false, 一样可以通过defaults去设置每个请求。我们也可以在每次请求覆盖设置。当同时发送2个没有缓存的请求时,angular也能处理,只发送一次。
var app = angular.module("app", []);
app.config(function ($httpProvider) {
$httpProvider.defaults.cache = true;
});
app.controller("ctrl", function ($scope, $http) {
//并发但是只会发送一个请求
$http.get("handle.ashx");
$http.get("handle.ashx");
//我们可以为每次请求要不要使用缓存或者缓存数据
$http({
url: "handle.ashx",
method: "GET",
cahce: true
});
$http({
url: "handle.ashx",
method: "GET",
cache : false //强制不使用缓存,即使已存在
});
});
$httpProvider.interceptors
(interceptors 中文是拦截的意思)。除了之前介绍过的 transform 可以对数据做一些处理, angular也提供了另外4个时刻,分别是 onRequest, onRequestFail, onResponse, onResponseFail。让我们做一些而外处理. 比如当我们server返回500的时候,可能我们想做一个通用的alert,或是request fail 的话自动调整一下config在尝试请求等等.
//interceptors是数组,放入的是可以依赖注入的方法哦!
$httpProvider.interceptors.push(["$q", function ($q) {
return {
request: function (config) { //config = {method, postData, url, headers} 等
return config; //返回一个新的config,可以做一些统一的验证或者调整等.
},
requestError: function (rejection) {
return $q.reject(rejection); //必须返回一个promise对象
},
response: function (response) {
return response; //这里也可以返回 promise, 甚至是把它给 $q.reject掉
},
responseError: function (rejection) { //rejection = { config, data, status, statusText, headers }
return $q.reject(rejection); //必须返回一个promise对象
}
};
}]);
transform 的执行次序是这样的 interceptors.request -> transformRequest -> transformResponse -> interceptors.response
判断视图是否渲染完成
// 指令
app.directive('eventNgRepeatDone', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attr) {
if (scope.$last) {
// $timeout(function () {
scope.$emit('eventNgRepeatDone');
if ($attrs.ngRepeatDone) {
$scope.$apply(function () {
$scope.$eval($attrs.ngRepeatDone);
});
}
//});
}
}
}
});
<!-- 使用 -->
<div ng-repeat = "item in list track by $index" event-ng-repeat-done>{{item.name}}</div>
app.controller('myCtrl', ['$scope', function ($scope) {
$scope.$on ('eventNgRepeatDone', function () {
// doSomething
});
});