web-dev-qa-db-fra.com

Angular Js et google api client.js (gapi)

Il m'a fallu un jour pour que cela fonctionne, alors je pense que mon expérience peut être utile à quelqu'un. Et peut-être que d'autres trouveront une amélioration.

Je lance donc angularJS il y a deux jours. Et je veux que cela fonctionne avec les points de terminaison Google Cloud pour créer une interface backend. Voici le problème pour moi.

Le client javascript pour gapi est livré avec un chargement asynchrone, donc l’initialisation angulaire va planter, ayant gapi non défini.

Vous devez donc initialiser angulaire lorsque gapi est initialisé:

  1. supprimer ng-app = "myApp"
  2. Ajouter <script src="https://apis.google.com/js/client.js?onload=googleOnLoadCallback"></script>
  3. Ajouter le rappel:

    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');  
    }
    

Sentez-vous bien, mais pourquoi pas un appel?

Alors voici le contrôleur:

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

Et voici le service: 

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();
            }
      });
   };
}]);

Et comme par magie, votre page se met à jour grâce à angular.

N'hésitez pas à marquer n'importe où je vais mal.

30
Samuel

Nice post et merci! Cette approche a fonctionné pour moi. L'ordre dans lequel le code apparaît dans votre fichier index.html peut être important. Cela n'a pas fonctionné pour moi tant que je n'avais pas les choses en ordre.

...
<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>
6
davedonohue

Bien que le progrès soit assez progressif, il convient également de mentionner angular-googleapi , qui encapsule joliment certains appels Google Agenda et Google Plus API et est facilement extensible. 

Vous devez ajouter ce bit à votre contrôleur lors de la vérification de l'autorisation:

$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();
4
fer

J'ai écrit une directive simple pour charger l'API Google Map de manière asynchrone:

// 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);
            }
        }
    };
}
})();

Ensuite, dans votre contrôleur principal, vous pouvez gérer l'événement:

// 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
        });
    }

})();

Il vous suffit de déclarer la directive dans votre balise 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>
3
Rémi Becheras

Regardez ceci: https://github.com/canemacchina/angular-google-client .

J'ai écrit ce module pour utiliser Google Api ou Google Cloud Endpoint dans une application Angular.

0
Canemacchina

J'ai utilisé une solution similaire à willlma, mais mon application utilise UI Router, il est donc impossible de savoir quel contrôleur sera appelé.

J'ai pu résoudre ce problème avec une promesse Javascript.

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);
            }
        }
    });
});
0
Derick

J'ai fait ce qui suit

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();

});
0
Harry Moreno

Donc, j'avais le même problème. Mettre ce code dans mon usine a fonctionné

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()

Fondamentalement, le problème consiste à appeler gapi.client avant son chargement. Si vous vérifiez simplement que le contenu est chargé, puis réessayez en une seconde (vous pouvez définir l'heure de votre choix, définissez-la sur une valeur inférieure si vous vous attendez à ce que l'utilisateur en ait besoin assez rapidement après le chargement de la page).

Je me débattais avec ça pendant un moment, et c'est tout ce qui a fonctionné pour moi ... J'espère que ça aide!

0
Cody Jacques