AngularJS + Cloud端点:跨多个控制器加载端点api

时间:2016-04-30 01:54:17

标签: angularjs google-app-engine google-cloud-endpoints gapi

我已根据这两个指南初始化了我的应用程序:

我的设置看起来像这样:

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)。这就是我们的代码:

  1. gapi客户端加载,然后调用init(),调用window.loadCloudEndpoints()
  2. cloudendpoints.init(postInit)加载 cloudendpoints 端点服务,然后调用postInit()回调。然后,我们可以在postInit()
  3. 中调用端点API

    当我们想要创建另一个控制器来处理我们应用的另一个视图时,就会遇到挑战。我们假设我们创建了一个ContentPageCtrl控制器 - 那么我们是否需要再次初始化我们的端点服务?我们如何让端点服务可供所有控制器使用而无需重复?

    我的Hacky解决方案 为了解决这个问题,我$watch the backend_ready以便我可能只在端点api加载后才开始进行gapi调用:

     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变量。我的方法感觉非常脏,并且有缩放问题。

    对此有什么更好的方法?

1 个答案:

答案 0 :(得分:2)

更好的方法是利用Promises的力量。然后,您可以将服务初始化一次(在服务函数内)以及您只需调用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
});