我已经按照以下两个指南初始化了我的应用程序:
-
AngularJS+云端点——构建现代Web应用程序的良方
-
Angular Js和谷歌api客户端.Js(gap)
我的设置看起来像这样:
app.js
function init() {
console.log('running global init()');
window.initgapi();
}
var app = angular.module('app', []);
// Main Controller
app.controller('MainCtrl', ['$scope', '$window', 'cloudendpoints', function($scope, $window, cloudendpoints) {
// this is called once eventapi is loaded
var postInit = function() {
$scope.backend_ready = true;
$scope.fetchContent();
};
$window.initgapi = function() {
cloudendpoints.init(postInit);
};
$scope.fetchContent = function() {
gapi.client.cloudendpoints
.getContent()
.execute(function(resp) {
// do something with response
});
};
}]);
cloudendpoints服务在它自己的文件cloudendpoints.js
:中
// for loading endpoints service
app.factory('cloudendpoints', [function cloudendpoints() {
var init = function(postInit) {
var restUrl = '//' + window.location.host + '/_ah/api';
gapi.client.load('cloudendpoints', 'v1', postInit, restUrl);
};
return { init: init };
}]);
最后,我们的脚本按以下顺序加载:
<script src="angular.min.js"></script>
<script src="app.js"></script>
<script src="controllers/mainCtrl.js"></script>
<script src="services/cloudendpoints.js"></script>
<script src="https://apis.google.com/js/client.js?onload=init"></script>
挑战到目前为止,这运行良好,因为我们只使用了一个控制器(MainCtrl
)。这就是我们代码中发生的情况:
- gap客户端加载,然后调用
init()
,后者调用window.loadCloudEndpoints()
cloudendpoints.init(postInit)
加载cloudendpoints端点服务,然后调用postInit()
回调。然后,我们可以从postInit()
中调用端点API
当我们想创建另一个控制器来处理应用程序的另一个视图时,就会出现挑战。假设我们创建了一个ContentPageCtrl
控制器——然后我们是否需要再次初始化我们的端点服务?我们如何使端点服务对所有控制器都可用,而不必重复?
我的破解解决方案为了解决这个问题,我$watch
the backend_ready
,这样我就只能在端点api加载后开始进行gap调用:
app.controller('ContentPageCtrl', ['$scope', function($scope) {
/**
* Make sure that the backend is ready before
* running any gapi.client.cloudendpoints calls
**/
$scope.$watch('backend_ready', function() {
if ($scope.backend_ready === true) {
gapi.client.cloudendpoints
.loadContent()
.execute(function(resp) {
// put content in DOM
});
}
});
}]);
这意味着我需要在每个需要进行端点调用的控制器中$watch
backend_ready
变量。我的方法感觉很肮脏,而且在扩展方面存在问题。
对此有什么更好的方法?
更好的方法是利用Promises
的功能。然后,您可以让Service init一次(在服务函数内),在每个方法上,您只需调用promise.then(...)
并保留特定于该方法的逻辑。以这个为例:
app.factory('cloudendpoints', ['$q','$timeout','$window',function cloudendpoints($q,$timeout,$window) {
var backend_ready = $q.defer();
checkLoaded();
function checkLoaded(){
if($window.gapi)
backend_ready.resolve();
else
$timeout(checkLoaded,100); //check again in 100ms
}
var init = function(postInit) {
var restUrl = '//' + window.location.host + '/_ah/api';
return backend_ready.promise.then(function(resp){
gapi.client.load('cloudendpoints', 'v1', postInit, restUrl);
}); //we are returning a promise so we can have more
//flexability inside the controllers (do stuff after the loaded api);
};
return {
init: init
};
}]);
//Somewhere inside a controller...
app.controller('someCtrl', ['cloudendpoints', function(cloudendpoints){
function postInit(){ ... }
cloudendpoints.init(postInit); //waits for gapi to load, then executes init
});