【问题标题】:Angular Js and google api client.js (gapi)Angular Js 和 google api client.js (gapi)
【发布时间】:2013-10-24 07:57:25
【问题描述】:

我花了一天的时间才使它起作用,所以我认为我的经验可能对某人有用。也许其他一些人会发现改进。

所以我两天前开始使用 angularJS。我希望它与 Google Cloud Endpoints 一起使用以创建后端界面。我的麻烦来了。

gapi 的 javascript 客户端带有异步加载,因此角度初始化会在 gapi 未定义的情况下崩溃。

所以你需要在 gapi 初始化时引导 angular:

  1. 删除 ng-app="myApp"
  2. 添加<script src="https://apis.google.com/js/client.js?onload=googleOnLoadCallback"></script>
  3. 添加回调:

    function googleOnLoadCallback(){  
        var apisToLoad = 1; // must match number of calls to gapi.client.load()  
        var gCallback = function() {  
            if (--apisToLoad == 0) {  
                //Manual bootstraping of the application  
                var $injector = angular.bootstrap(document, ['myApp']);  
                console.log('Angular bootstrap complete ' + gapi);  
            };  
        };  
        gapi.client.load('helloWorld', 'v1', gCallback, '//' + window.location.host + '/_ah/api');  
    }
    

感觉不错,但来个电话怎么样?

所以这里是控制器:

angular.module('myApp.controllers', []).  
    .controller('MyCtrl', ['$scope' ,'helloWorldService',  
        function($scope,greetingsService) {
          helloWorldService.loadData($scope);  
    }]);

这里是服务:

angular.module('myApp.services', [])
service('helloWorldService', [function() {
   this.loadData = function($scope)  {
     //Async call to google service
     gapi.client.helloWorld.greetings.listGreeting().execute(
        function(resp) {
            if (!resp.code) {
                console.debug(resp);
                $scope.greetings = resp.items;
                // Because it's a callback,
                // we need to notify angular of the data refresh...
                $scope.$apply();
            }
      });
   };
}]);

由于 Angular,您的页面会神奇地更新。

如有错误,请随时标记。

【问题讨论】:

  • 嗨@Samuel 它不工作。我被困在这个问题上。能不能说的详细点。
  • 谢谢,这很好用。
  • 感谢您发布这个 - 帮了我很多:)
  • 只是一个优化说明:$scope.$digest 在此处使用会更好,因为它仅在当前 $scope 对象上开始一个摘要循环; $scope.$apply 的成本更高,因为它启动了一个应用范围的摘要周期。
  • angular2 有转机吗?

标签: javascript angularjs google-app-engine google-cloud-endpoints google-api-js-client


【解决方案1】:

不错的帖子,谢谢!这种方法对我有用。代码出现在 index.html 文件中的顺序可能很重要。直到我按此顺序处理后,它才对我有用。

...
<script>
  function googleOnLoadCallback(){
      alert('googleOnLoadCallback called');
      var apisToLoad = 1; // must match number of calls to gapi.client.load()
      var gCallback = function() {
          if (--apisToLoad == 0) {
              //Manual bootstraping of the application
              var $injector = angular.bootstrap(document, ["myApp"]);
              console.log("myApp bootstrap complete " + gapi);
          };
      };
      gapi.client.setApiKey("my_client_id");
      gapi.client.load("translate", "v2", gCallback);

  }
</script>
<!-- See https://developers.google.com/api-client-library/javascript/samples/samples -->
<script src="https://apis.google.com/js/client.js?onload=googleOnLoadCallback"></script>
</head>

【讨论】:

    【解决方案2】:

    我做了以下

    gapi-service.js

    'use strict';
    
    app.factory('Gapi', ['ENV', function(ENV) {
    
    return {
    load: function load() {
      console.log('loading google apis...');
      if (typeof gapi.client === 'undefined') {
        setTimeout(load, 500);
      } else {
        gapi.client.setApiKey(ENV.googleToken);
        gapi.client.load('storage', 'v1', function() {
          console.log('loaded! :)');
          var request = gapi.client.storage.buckets.list({ project: ''});
          console.log(request);
          request.execute(function(response) { console.log(response); });
        });
      }
    }
      };
    }]);
    

    index.html

    <!DOCTYPE html>
    <html>
      <head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
    <title>"Txtbinge"</title>
      </head>
    
      <body ng-app="myApp">
    <script src="bower_components/jquery/dist/jquery.js"></script>
    <script src="bower_components/angular/angular.js"></script>
    
    <script src="scripts/client.js"></script>
    <script src="scripts/app.js"></script>
    <script src="scripts/gapi-service.js"></script>
    
    
      </body>
    </html>
    

    controllers.js

    'use strict';
    
    app.controller('AppController', function($scope, $state, Camera, Gapi) {
    
      Gapi.load();
    
    });
    

    【讨论】:

    • 查看我的回答,了解如何避免设置计时器。
    【解决方案3】:

    虽然进展非常快,但也值得一提angular-googleapi,它很好地封装了一些 Google 日历和 Google Plus API 调用,并且易于扩展。

    您需要在检查授权时将此位添加到您的控制器:

    $scope.authenticated = false;
    
    $scope.$on("google:authenticated", function(){
       $scope.authenticated = true;
       $scope.$on('googleCalendar:loaded', function(){
           # work your magic here
           # $scope.calendars = googleCalendar.listCalendars();
           # $scope.$apply();
       });
    });
    
    function checkAuth() {
       setTimeout(function(){
           gapi.auth === undefined ? checkAuth() : googleLogin.checkAuth();
       }, 20);
    }
    
    checkAuth();
    

    【讨论】:

    • 不确定我是否完全理解。但是为什么我们不能将 checkAuth() 附加到提供者?好像舒服多了。谢谢你的建议。
    【解决方案4】:

    与引导或设置超时相比,在您发出服务器请求之前/期间让 Angular 加载是最有效的。我按照AngularJS + Cloud Endpoints: A Recipe for Building Modern Web Applications 中描述的建议进行了以下操作。

    像往常一样保持ng-app 指令(无引导)

    <html ng-app="myApp">
    <head>
      <script src="angular.js" type="text/javascript"></script>
      <script src="app.js" type="text/javascript"></script>
      <script src="https://apis.google.com/js/client.js?onload=init"></script>
    </head>
    <body ng-show="backendReady">
    

    在您的 JS 中的任意位置为 GAPI 回调函数创建一个全局变量

    var app = angular.module('myApp', []);
    
    var init = function() {
      window.initGapi();
    }
    
    app.controller('MainController', function($scope, $window, gapiService) {
      var postInitiation = function() {
        // load all your assets
      }
      $window.initGapi = function() {
        gapiService.initGapi(postInitiation);
      }
    });
    
    app.service('gapiService', function() {
      this.initGapi = function(postInitiation) {
        gapi.client.load('helloWorld', 'v1', postInitiation, restURL);
      }
    });
    

    来自上面的链接:

    您不想在第一个 init() 方法中执行初始化的原因是您可以将尽可能多的代码放在 AngularJS 世界中,例如控制器、服务和指令。因此,您可以充分利用 AngularJS 的强大功能并进行所有单元测试、集成测试等。

    这似乎是一种迂回的做事方式,但它优化了速度、可测试性、关注点分离。

    【讨论】:

    • @CadeThacker 你的编辑被拒绝了,但它是正确的,所以我复制了它。谢谢。
    • 在那里查看我的答案。 TLDR:为initinitGapi 使用不同的函数名称
    • 嗨,Willma,我正在尝试使用这种方法。但是我遇到了一个错误,说 window.initGapi 没有定义。我在绑定到 Body 的 BaseControler 中定义方法。
    • 嗯,但是请找出为什么单位会在控制器之前死亡。用你的代码提出问题,我会看看。
    【解决方案5】:

    我写了一个简单的指令来异步加载谷歌地图 API:

    // js/directives/gmapAsync.js
    
    (function(){
    'use strict';
    
    angular.module('app').directive('gmapAsync',
        ['$window', '$rootScope', gmapAsync]
    );
    
    function gmapAsync($window, $rootScope){
    
        var gmapScript = $window.document.createElement('script');  
    
        $window.onGmapScriptLoaded = function(){
            console.log('google maps script loaded');
    
            $rootScope.gmapApiLoaded = true;
            $rootScope.$broadcast('gmap.api.loaded');
    
        };
    
        return {
            restrict: 'A',
            transclude: false,
            scope:false,
            link:   function(scope, element, attributes){
    
                if (navigator.onLine) {
                    appendScript();
                } else {
                    $window.addEventListener('online',appendScript);
                }
    
                function appendScript(){
                    gmapScript.type = 'text/javascript';
                    gmapScript.src = 'https://maps.googleapis.com/maps/api/js?v=3.exp&' + 'callback=onGmapScriptLoaded';
                    $window.document.body.appendChild(gmapScript);
                }
            }
        };
    }
    })();
    

    然后在你的主控制器中,你可以处理事件:

    // js/controllers/AppCtrl.js
    
    (function(){
    'use strict';
    
        angular.module('app').controller('AppCtrl',[$scope,AppCtrl])
    
        function AppCtrl($scope){
    
            $scope.$on('gmap.api.loaded',function(){
                // your stuff to init after the api is loaded
            });
        }
    
    })();
    

    你只需要在你的 body 标签中声明指令:

    <!DOCTYPE html>
    <html>
    
        <head></head>
    
        <body data-ng-app="app" data-gmap-async data-ng-controller="AppCtrl">
    
            <!-- template body -->
    
            <script type="text/javascript" src="js/app.js"></script>
            <script type="text/javascript" src="js/controllers/AppCtrl.js"></script>
            <script type="text/javascript" src="js/directives/gmapAsync.js"></script>
        </body>
    
    </html>
    

    【讨论】:

      【解决方案6】:

      看看这个:https://github.com/canemacchina/angular-google-client

      我已编写此模块以在 Angular 应用程序中使用 Google Api 或 Google Cloud Endpoint。

      【讨论】:

        【解决方案7】:

        所以我遇到了同样的问题。将此代码放在我的工厂中工作

        var initialize = function() {
            if(gapi.client == undefined) {
                setTimeout(function() {
                    initialize()
                }, 1000);
            } else {
                gapi.client.setApiKey("<api_key>");
                gapi.client.load('youtube', 'v3').then(function() {
                    console.log("youtube is ready")
                });
            }
        };
        
        initialize()
        

        基本上,问题是在加载之前尝试调用 gapi.client。如果您只是检查它是否已加载,如果没有,请稍后再试(您可以根据需要设置任何时间,如果您希望用户在页面加载后相对较快地需要此时间,请将其设置为较低)。

        我为此苦苦挣扎了一段时间,这对我有用...希望这会有所帮助!

        【讨论】:

          【解决方案8】:

          我使用了类似于 willlma 的解决方案,但我的应用程序使用 UI Router,因此不知道将调用哪个控制器。

          我能够通过 Javascript Promise 解决这个问题。

          index.html

          <html ng-app="myApp">
          <head>
              <script src="angular.js" type="text/javascript"></script>
              <script src="app.js" type="text/javascript"></script>
              <script src="https://apis.google.com/js/client.js?onload=init">
          </head>
          

          app.js

          var app = angular.module('myApp', []);
          
          app.controller('MainController', function($scope, gapiService) {
              gapiService.then(function(gapi) {
                  // You can use gapi normally here;
              });
          });
          
          app.service('gapiService', function($window) {
              return new Promise(function(resolve, reject) {
                  if ($window.gapi !== undefined) {
                      console.log("Have gapi already");
                      resolve($window.gapi);
                  } else {
                      console.log("Waiting for gapi");
                      $window.init = function() {
                          resolve($window.gapi);
                      }
                  }
              });
          });
          

          【讨论】:

            猜你喜欢
            • 2015-10-10
            • 2015-03-12
            • 2017-08-15
            • 2019-09-11
            • 2014-01-14
            • 2021-01-12
            • 2018-01-20
            • 2018-08-05
            • 1970-01-01
            相关资源
            最近更新 更多