我们知道默认的路由提供(Route Provider)在复杂的应用程序中是不太适合应用场景,它存在诸多限制,所以在Angular 1.2之后此时我们不得不将路由提供作为一个单独的模块当我们需要使用时即ngRoute,但是该ngRoute使用起来还是不够灵活,AngularJS团队很快意识到了这点,于是提出了ui.router作为ngRoute的完美替代品。
此节我们要讨论关于Route的高级,也就是深入探讨AngularUi Router中的比较高级的内容,关于ui.router有如下强大特点:
(1)嵌套状态和嵌套视图。
(2)多个命名视图(由一个视图到另外一个视图通过引用视图的名称)。
(3)嵌套解析(一个解析等待另外一个解析完毕)。
(4)ui.sref指令(绑定超链接,并自动生成)。
......
对于本节我们则要讲述的是路由的resolve,在ngRoute中也存在resolve,ui.router中的resolve相比较更加强大,于是对于ngRoute中的Resolve未做过多探讨,有兴趣的童鞋可以自行去学习,那resolve到底是做什么的?它可以在一个路由中提前加载数据,接着这个resolve中的属性会被注入到此路由的控制器中,ui.router中的reolve应该是该路由模块中最大的特性。当resolve中的全部属性被解析完毕时,resolve才会执行,意味着是延迟执行。下面我们来一步一步看看resolve。
通过在resolve中通过函数返回一个字符串,此时会立即被解析。我们来看看。
<html> <head> <meta charset="UTF-8"> <title></title> <script type="text/javascript" src="../Scripts/angular.min.js"></script> <script src="../ui-router/angular-ui-router.min.js"></script> <script src="app.js"></script> </head> <body ng-app="app"> <div ui-view></div> </body> </html>
angular.module("app",["ui.router"]) .config(config); function config($stateProvider,$urlRouterProvider){ $urlRouterProvider.otherwise("/resolve"); $stateProvider.state("resolve",{ url:"/resolve", templateUrl:"resolve.html", resolve: { cnblogs:function(){ return "xpy0928"; } }, controller: function($scope, cnblogs){ $scope.loadData = cnblogs; } }); }
我们接着在视图resolve.html中显示绑定的数据 {{loadData}} 结果毫无疑问显示xpy0928。
上述我们是在视图内部定义的控制器从而绑定数据,如果我们的Application足够大,此时路由势必会膨胀,在这种情况下,我们还是单独定义控制器并绑定数据,如下:
function config($stateProvider,$urlRouterProvider){ $urlRouterProvider.otherwise("/resolve"); $stateProvider.state("resolve",{ url:"/resolve", templateUrl:"resolve.html", controller:"resolveVM", resolve: { cnblogs:function(){ return "xpy0928"; } } }); } angular.module("app").controller("resolveVM",function($scope,cnblogs){ $scope.loadData = cnblogs; });
同时我们也应该注意,当我们没有宿主运行时,对于有些浏览器可能会出现违背了跨域,在AnuglarJS中启动跨域,可以进行如下操作:
$httpProvider.defaults.useXDomain = true; delete $httpProvider.defaults.headers.common['X-Requested-With'];
上述对于简单使用resolve给出了一个基本的例子,我们再往下面看看。
我们首先看看一个最简单返回promise的例子。我们只需在上述app.js中的resolve进行如下修改:
resolve: { promiseObj: function($http){ return $http({method: 'GET', url: ''}); },
貌似还是不太乐观,下面我们详细介绍下,一般对于resolve无非就是通过resource即http请求来返回数据当然或者通过服务来获取数据。上述是我们简单的返回一个promise,我们完全可以自定义一个promise。将resolve修改如下:
resolve: { delayedData: function($q, $timeout) { var deferred = $q.defer(); $timeout(function() { var myData = {message: 'hello,everyone!xpy0928 from cnblogs'}; deferred.resolve(myData); }, 1000); return deferred.promise; } }
接下来我们来绑定数据:
angular.module("app").controller("resolveVM",function($scope,delayedData){ $scope.loadData = delayedData; });
诶,貌似没图,还是演示下:
上述有说过我们利用resolve无非根据http获取数据,在AngularJS中利用ngResource来实现(推荐前面的替代品,这里只是作为演示用)。
我们如下修改resolve:
resolve: { userData: function(userList) { var list = userList.query(); return list.$promise; } }
创建获取用户列表服务:
angular.module("app").factory('userList', ['$resource', function ($resource) { return $resource('http://localhost:52005/api/cnblogs/getUserlist'); }]); angular.module("app").controller("resolveVM",function($scope,userData){ $scope.loadData = userData; });
我们看下效果:
上述只是利用resolve解析一个promise,若我们要在路由或者状态发生改变之前解析多个promise,此时我们该如何做?我们此时利用$q.all开完成,我们来看如下代码:
resolve: { userData: function($q,userList,blogList) { var list = userList.query(); var bloglist = blogList.query(); return $q.all([list.$promise,blogList.$promise]) .then(function(){ }) } }
通过resource获取数据:
angular.module("app").factory('userList', ['$resource', function ($resource) { return $resource('http://localhost:52005/api/cnblogs/getUserlist'); }]); angular.module("app").factory('blogList', ['$resource', function ($resource) { return $resource('http://localhost:52005/api/cnblogs/getBloglist'); }]);
如上,就是这么简单。
本节我们讲了路由中比较高级的知识resolve,建议在实际开发中利用ui.router来完成而非ngRouter中的resolve,同时本节也涉及到了$q/promise,本节未进行详细阐述,下节我们我们仔细讲讲$q或者其他知识。
本打算再写一篇关于promise的文章,搜到一篇写的非常好的文章,那就不再讲述了链接如下:
AngularJS 中的Promise和设计模式: http://my.oschina.net/ilivebox/blog/293771?p=1