我正在使用AngularJS和Google Cloudendpoint建立一个网站
架构如下。我有:
1 - 管理整个站点显示的MainCtrl(顶层菜单,模态等......)
<body ng-controller="MainCtrl" ng-cloak main-directive>
...
<div ng-view></div>
...
</body>
2-ng-view,每个页面都有一个控制器,每个页面都有一个由$ routeprovider管理的自己的控制器
main.js
.config([
'$routeProvider',
'$locationProvider',
'$httpProvider',
function($routeProvider, $locationProvider, $httpProvider) {
...
$routeProvider.when('/example', {
templateUrl : 'partials/example.html',
controller : 'ExampleCtrl',
access : accessLevels.PUBLIC
}
...
$routeProvider.otherwise({redirectTo: '/'});
}
MainCtrl需要对Google Cloud Endpoint进行异步调用才能使会话看起来像这样。
gapi.client.myapi.app.init().execute(function(resp){});
到目前为止,我所做的是将该代码包装在MainCtrl调用的Service函数中,然后在initDone值上的每个子控制器中监视,当异步调用完成时,在MainCtrl中更新。
MainCtrl
SessionService.init().then(function(data){
$scope.initDone = SessionService.getInitDone();
});
服务
angular.module('myapp.services').service('SessionService', function ($http, $q, $rootScope) {
this.initDone = false
this.session = {}
this.init = function(){
var s = this;
var deferred = $q.defer();
gapi.client.myapi.app.init().execute(function(resp){
deferred.resolve(resp);
s.initDone = true;
});
return deferred.promise;
}
this.getInitDone = function(){
return this.initDone;
}
});
ExampleCtrl
angular.module('myapp.controllers').controller('ExampleCtrl', function MainCtrl($scope, $timeout, $log, $location, SessionService) {
$scope.$watch('initDone', function(newVal, oldVal){
$scope.testValue = SessionService.getInitDone()
})
});
虽然这项工作我不确定这是正确的解决方案。我想要的是能够让ng-view等待直到MainCtrl完成他的工作。
因为按照我的方式进行操作意味着一旦对端点的调用得到更新,就会显示ng-view,这对于用户预期来说看起来不太好。
我尝试在$ routeProvider中使用解析并从那里执行API调用,但是然后我的MainCtrl没有正确获取会话值。
我的解决方案是做一个:
$routeProvider.when('/example', {
templateUrl : 'partials/example.html',
controller : 'ExampleCtrl',
access : accessLevels.PUBLIC,
resolve : MainCtrl.init
}
但$ routeProvider
中没有MainCtrl另一个想法是拦截ng-view调用,但我不知道在哪里这样做并且可以同时访问服务。
感谢您的任何想法/帮助
修改
我试着在main.js
中做这样的事情 $routeProvider.when('/example', {
templateUrl : 'partials/example.html',
controller : 'ExampleCtrl',
access : accessLevels.PUBLIC,
resolve: {
sessionData: ["$q", "SessionService", function($q, SessionService) {
//console.log(SessionService.getTest())
var deferred = $q.defer();
gapi.client.myapi.app.init().execute(function(resp){
deferred.resolve(resp);
});
return deferred.promise;
}]
});
如果我希望每个子控制器调用api,哪个有效。我想要的是让子控制器使用MainCtrl准备好后初始化的任何东西。基本上只在MainCtrl准备就绪时加载视图和相关的控制器(包括异步调用
)答案 0 :(得分:6)
根据以下评论进行编辑
这个想法是用ng-if阻止视图,直到api调用返回:
// Session service
this.init = function(){
if (!this.initDone){
var s = this;
var deferred = $q.defer();
gapi.client.myapi.app.init().execute(function(resp){
deferred.resolve(resp);
s.initDone = true;
});
return deferred.promise;
}
}
// MainController.js :
$scope.initDone = false;
SessionService.init().then(function(
$scope.initDone = SessionService.getInitDone();
});
// index.html:
<div ng-if="initDone">
<div id="view" ng-view> </div>
</div>
旧答案: 您是否可以将对Google的异步调用移至服务并让该服务返回承诺
myApp.service('DataService', ['$rootScope', '$http', function ($rootScope, $http) {
var promise = $http.get("http://google.com/theservice").success(function (data) {
......
});
this.promise = promise
在您的路由设置中,有一个解决方案,等待在Google服务调用返回后唯一加载控制器
when('/example', {templateUrl: 'partials/example.html',
controller: 'ExampleCtrl',
resolve: {
'MyServiceData': function (DataService) {
return DataService.promise;
}
}}).
编辑:看看如何返回api通话的承诺https://stackoverflow.com/a/16117041/514463