Mis*_*ery 319 javascript angularjs angularjs-routing
我想知道是否有一种方法(类似于Gmail)AngularJS 延迟显示新路由,直到每个模型及其数据已使用其各自的服务获取.
例如,如果ProjectsController
列出了所有项目以及project_index.html
显示这些项目的模板,Project.query()
则会在显示新页面之前完全获取.
在此之前,旧页面仍将继续显示(例如,如果我正在浏览另一个页面,然后决定查看此项目索引).
Mis*_*ery 374
$ routeProvider resolve属性允许延迟路由更改,直到加载数据.
首先使用这样的resolve
属性定义路由.
angular.module('phonecat', ['phonecatFilters', 'phonecatServices', 'phonecatDirectives']).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/phones', {
templateUrl: 'partials/phone-list.html',
controller: PhoneListCtrl,
resolve: PhoneListCtrl.resolve}).
when('/phones/:phoneId', {
templateUrl: 'partials/phone-detail.html',
controller: PhoneDetailCtrl,
resolve: PhoneDetailCtrl.resolve}).
otherwise({redirectTo: '/phones'});
}]);
Run Code Online (Sandbox Code Playgroud)
注意该resolve
属性是在路线上定义的.
function PhoneListCtrl($scope, phones) {
$scope.phones = phones;
$scope.orderProp = 'age';
}
PhoneListCtrl.resolve = {
phones: function(Phone, $q) {
// see: https://groups.google.com/forum/?fromgroups=#!topic/angular/DGf7yyD4Oc4
var deferred = $q.defer();
Phone.query(function(successData) {
deferred.resolve(successData);
}, function(errorData) {
deferred.reject(); // you could optionally pass error data here
});
return deferred.promise;
},
delay: function($q, $defer) {
var delay = $q.defer();
$defer(delay.resolve, 1000);
return delay.promise;
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,控制器定义包含一个解析对象,该对象声明了控制器构造函数可用的内容.这里phones
注入控制器并在resolve
属性中定义.
该resolve.phones
函数负责返回一个promise.收集所有承诺并延迟路线更改,直到所有承诺得到解决.
工作演示:http://mhevery.github.com/angular-phonecat/app/#/phones 资料来源:https://github.com/mhevery/angular-phonecat/commit/ba33d3ec2d01b70eb5d3d531619bf90153496831
mb2*_*b21 51
这是一个适用于Angular 1.0.2的最小工作示例
模板:
<script type="text/ng-template" id="/editor-tpl.html">
Editor Template {{datasets}}
</script>
<div ng-view>
</div>
Run Code Online (Sandbox Code Playgroud)
JavaScript的:
function MyCtrl($scope, datasets) {
$scope.datasets = datasets;
}
MyCtrl.resolve = {
datasets : function($q, $http) {
var deferred = $q.defer();
$http({method: 'GET', url: '/someUrl'})
.success(function(data) {
deferred.resolve(data)
})
.error(function(data){
//actually you'd want deffered.reject(data) here
//but to show what would happen on success..
deferred.resolve("error value");
});
return deferred.promise;
}
};
var myApp = angular.module('myApp', [], function($routeProvider) {
$routeProvider.when('/', {
templateUrl: '/editor-tpl.html',
controller: MyCtrl,
resolve: MyCtrl.resolve
});
});?
?
Run Code Online (Sandbox Code Playgroud)
精简版:
由于$ http()已经返回一个promise(也称为deferred),我们实际上不需要创建自己的.所以我们可以简化MyCtrl.决心:
MyCtrl.resolve = {
datasets : function($http) {
return $http({
method: 'GET',
url: 'http://fiddle.jshell.net/'
});
}
};
Run Code Online (Sandbox Code Playgroud)
$ http()的结果包含数据,状态,标题和配置对象,因此我们需要将MyCtrl的主体更改为:
$scope.datasets = datasets.data;
Run Code Online (Sandbox Code Playgroud)
bit*_*wit 32
我看到有些人在使用带有缩小友好依赖注入的angular.controller方法时询问如何执行此操作.由于我刚开始工作,我觉得有必要回来帮忙.这是我的解决方案(从原始问题和Misko的答案中采用):
angular.module('phonecat', ['phonecatFilters', 'phonecatServices', 'phonecatDirectives']).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/phones', {
templateUrl: 'partials/phone-list.html',
controller: PhoneListCtrl,
resolve: {
phones: ["Phone", "$q", function(Phone, $q) {
var deferred = $q.defer();
Phone.query(function(successData) {
deferred.resolve(successData);
}, function(errorData) {
deferred.reject(); // you could optionally pass error data here
});
return deferred.promise;
]
},
delay: ["$q","$defer", function($q, $defer) {
var delay = $q.defer();
$defer(delay.resolve, 1000);
return delay.promise;
}
]
},
}).
when('/phones/:phoneId', {
templateUrl: 'partials/phone-detail.html',
controller: PhoneDetailCtrl,
resolve: PhoneDetailCtrl.resolve}).
otherwise({redirectTo: '/phones'});
}]);
angular.controller("PhoneListCtrl", [ "$scope", "phones", ($scope, phones) {
$scope.phones = phones;
$scope.orderProp = 'age';
}]);
Run Code Online (Sandbox Code Playgroud)
由于此代码源自问题/最受欢迎的答案,因此未经测试,但如果您已经了解如何制作缩小友好的角度代码,它应该向您发送正确的方向.我自己的代码不需要的那一部分是在"手机"的解析功能中注入"电话",我根本也没有使用任何"延迟"对象.
我也推荐这个youtube视频http://www.youtube.com/watch?v=P6KITGRQujQ&list=UUKW92i7iQFuNILqQOUOCrFw&index=4&feature=plcp,这对我帮助很大
如果您感兴趣的话,我决定也粘贴我自己的代码(写在coffeescript中),这样你就可以看到我是如何工作的.
仅供参考,我提前使用通用控制器来帮助我在几个型号上进行CRUD:
appModule.config ['$routeProvider', ($routeProvider) ->
genericControllers = ["boards","teachers","classrooms","students"]
for controllerName in genericControllers
$routeProvider
.when "/#{controllerName}/",
action: 'confirmLogin'
controller: 'GenericController'
controllerName: controllerName
templateUrl: "/static/templates/#{controllerName}.html"
resolve:
items : ["$q", "$route", "$http", ($q, $route, $http) ->
deferred = $q.defer()
controllerName = $route.current.controllerName
$http(
method: "GET"
url: "/api/#{controllerName}/"
)
.success (response) ->
deferred.resolve(response.payload)
.error (response) ->
deferred.reject(response.message)
return deferred.promise
]
$routeProvider
.otherwise
redirectTo: '/'
action: 'checkStatus'
]
appModule.controller "GenericController", ["$scope", "$route", "$http", "$cookies", "items", ($scope, $route, $http, $cookies, items) ->
$scope.items = items
#etc ....
]
Run Code Online (Sandbox Code Playgroud)
Max*_*ann 18
此提交是版本1.1.5及更高版本的一部分,它公开了$promise
对象$resource
.包含此提交的ngResource版本允许解析如下资源:
$ routeProvider
resolve: {
data: function(Resource) {
return Resource.get().$promise;
}
}
Run Code Online (Sandbox Code Playgroud)
调节器
app.controller('ResourceCtrl', ['$scope', 'data', function($scope, data) {
$scope.data = data;
}]);
Run Code Online (Sandbox Code Playgroud)
nul*_*ull 16
这个片段是依赖注入友好(我甚至用它在组合ngmin和丑化),这是一个更优雅的领域驱动基础的解决方案.
以下示例注册Phone 资源和常量 phoneRoutes,其中包含该(电话)域的所有路由信息.在提供的答案中我不喜欢的是解析逻辑的位置- 主模块不应该知道任何事情或者对资源参数提供给控制器的方式感到困扰.这样逻辑就会停留在同一个域中.
注意:如果你正在使用ngmin(如果你不是:你应该),你只需要用DI数组约定来编写解析函数.
angular.module('myApp').factory('Phone',function ($resource) {
return $resource('/api/phone/:id', {id: '@id'});
}).constant('phoneRoutes', {
'/phone': {
templateUrl: 'app/phone/index.tmpl.html',
controller: 'PhoneIndexController'
},
'/phone/create': {
templateUrl: 'app/phone/edit.tmpl.html',
controller: 'PhoneEditController',
resolve: {
phone: ['$route', 'Phone', function ($route, Phone) {
return new Phone();
}]
}
},
'/phone/edit/:id': {
templateUrl: 'app/phone/edit.tmpl.html',
controller: 'PhoneEditController',
resolve: {
form: ['$route', 'Phone', function ($route, Phone) {
return Phone.get({ id: $route.current.params.id }).$promise;
}]
}
}
});
Run Code Online (Sandbox Code Playgroud)
下一部分是在模块处于配置状态时注入路由数据并将其应用于$ routeProvider.
angular.module('myApp').config(function ($routeProvider,
phoneRoutes,
/* ... otherRoutes ... */) {
$routeProvider.when('/', { templateUrl: 'app/main/index.tmpl.html' });
// Loop through all paths provided by the injected route data.
angular.forEach(phoneRoutes, function(routeData, path) {
$routeProvider.when(path, routeData);
});
$routeProvider.otherwise({ redirectTo: '/' });
});
Run Code Online (Sandbox Code Playgroud)
使用此设置测试路由配置也非常简单:
describe('phoneRoutes', function() {
it('should match route configuration', function() {
module('myApp');
// Mock the Phone resource
function PhoneMock() {}
PhoneMock.get = function() { return {}; };
module(function($provide) {
$provide.value('Phone', FormMock);
});
inject(function($route, $location, $rootScope, phoneRoutes) {
angular.forEach(phoneRoutes, function (routeData, path) {
$location.path(path);
$rootScope.$digest();
expect($route.current.templateUrl).toBe(routeData.templateUrl);
expect($route.current.controller).toBe(routeData.controller);
});
});
});
});
Run Code Online (Sandbox Code Playgroud)
在我最近(即将开始)的实验中,你可以看到它的全部荣耀.虽然这种方法对我来说很好,但我真的很想知道为什么$ injector注入器在检测到任何作为promise对象的注入时不会延迟构造任何东西.它会让事情变得更加容易.
编辑:使用Angular v1.2(rc2)
jps*_*ons 11
延迟显示路线肯定会导致异步纠结......为什么不简单地跟踪主实体的加载状态并在视图中使用它.例如,在您的控制器中,您可以在ngResource上同时使用成功和错误回调:
$scope.httpStatus = 0; // in progress
$scope.projects = $resource.query('/projects', function() {
$scope.httpStatus = 200;
}, function(response) {
$scope.httpStatus = response.status;
});
Run Code Online (Sandbox Code Playgroud)
然后在视图中你可以做任何事情:
<div ng-show="httpStatus == 0">
Loading
</div>
<div ng-show="httpStatus == 200">
Real stuff
<div ng-repeat="project in projects">
...
</div>
</div>
<div ng-show="httpStatus >= 400">
Error, not found, etc. Could distinguish 4xx not found from
5xx server error even.
</div>
Run Code Online (Sandbox Code Playgroud)
我从上面的Misko代码开始工作,这就是我用它做的.这是一个更新的解决方案,因为$defer
已经改为$timeout
.$timeout
然而,替换将等待超时期限(在Misko的代码中,1秒),然后返回数据,希望它及时得到解决.通过这种方式,它尽快返回.
function PhoneListCtrl($scope, phones) {
$scope.phones = phones;
$scope.orderProp = 'age';
}
PhoneListCtrl.resolve = {
phones: function($q, Phone) {
var deferred = $q.defer();
Phone.query(function(phones) {
deferred.resolve(phones);
});
return deferred.promise;
}
}
Run Code Online (Sandbox Code Playgroud)
使用AngularJS 1.1.5语法更新Justen答案中的"手机"功能.
原版的:
phones: function($q, Phone) {
var deferred = $q.defer();
Phone.query(function(phones) {
deferred.resolve(phones);
});
return deferred.promise;
}
Run Code Online (Sandbox Code Playgroud)
更新:
phones: function(Phone) {
return Phone.query().$promise;
}
Run Code Online (Sandbox Code Playgroud)
由于Angular团队和贡献者,所以要短得多.:)
这也是Maximilian Hoffmann的答案.显然,提交使其成为1.1.5.
您可以使用$ routeProvider resolve属性来延迟路由更改,直到加载数据.
angular.module('app', ['ngRoute']).
config(['$routeProvider', function($routeProvider, EntitiesCtrlResolve, EntityCtrlResolve) {
$routeProvider.
when('/entities', {
templateUrl: 'entities.html',
controller: 'EntitiesCtrl',
resolve: EntitiesCtrlResolve
}).
when('/entity/:entityId', {
templateUrl: 'entity.html',
controller: 'EntityCtrl',
resolve: EntityCtrlResolve
}).
otherwise({redirectTo: '/entities'});
}]);
Run Code Online (Sandbox Code Playgroud)
请注意,该resolve
属性是在路由上定义的.
EntitiesCtrlResolve
并且EntityCtrlResolve
是与控制器在同一文件中定义的常量对象.EntitiesCtrl
EntityCtrl
// EntitiesCtrl.js
angular.module('app').constant('EntitiesCtrlResolve', {
Entities: function(EntitiesService) {
return EntitiesService.getAll();
}
});
angular.module('app').controller('EntitiesCtrl', function(Entities) {
$scope.entities = Entities;
// some code..
});
// EntityCtrl.js
angular.module('app').constant('EntityCtrlResolve', {
Entity: function($route, EntitiesService) {
return EntitiesService.getById($route.current.params.projectId);
}
});
angular.module('app').controller('EntityCtrl', function(Entity) {
$scope.entity = Entity;
// some code..
});
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
154245 次 |
最近记录: |