Angular Js e google api client.js (gapi)

Levei um dia para fazer isso funcionar, então acho que minha experiência pode ser útil para alguém. E talvez alguns outros encontrem melhorias.

Então eu começo angularJS dois dias atrás. E eu quero que funcione com o Google Cloud Endpoints para criar uma interface de back-end. Aqui vem o problema para mim.

O cliente javascript para gapi vem com carregamento asynchronous, portanto, a boot angular falhará tendo lacunas indefinidas.

Então você precisa inicializar angular quando o gapi é inicializado:

  1. remova o ng-app = “myApp”
  2. Adicionar
  3. Adicione o retorno de chamada:

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

Sinta-se bem, mas que tal uma binding?

Então aqui está o controlador:

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

E aqui está o serviço:

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

E magicamente sua página atualiza graças ao angular.

Sinta-se livre para marcar em qualquer lugar que eu esteja errado.

Em vez de inicializar ou definir um tempo limite, é mais eficiente permitir que o Angular seja carregado antes / enquanto você estiver fazendo as solicitações do servidor. Segui o conselho descrito em AngularJS + Cloud Endpoints: uma receita para a criação de aplicativos da Web modernos , que faz o seguinte.

Mantenha sua diretiva ng-app como de costume (sem bootstrapping)

        

Crie uma variável global para a function de retorno de chamada GAPI em qualquer lugar no seu JS

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

Do link acima:

O motivo pelo qual você não deseja executar a boot no primeiro método init () é para que você possa colocar o máximo de código possível no mundo do AngularJS, como controladores, serviços e diretivas. Como resultado, você pode aproveitar todo o poder do AngularJS e ter todos os testes de unidade, testes de integração e assim por diante.

Isso pode parecer uma maneira indireta de fazer as coisas, mas otimiza a velocidade, a testabilidade e a separação de interesses.

Nice post e obrigado! Essa abordagem funcionou para mim. Pode importar a ordem em que o código aparece no seu arquivo index.html. Não funcionou para mim até que eu tivesse coisas nessa ordem.

 ...     

Embora praticamente em progresso, talvez valha a pena mencionar o angular-googleapi , que envolve muito algumas chamadas de API do Google Agenda e Google Plus e é facilmente extensível.

Você precisaria adicionar esse bit ao seu controlador ao verificar a autorização:

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

Eu escrevi uma diretiva simples para carregar a API do Google Maps de forma assíncrona:

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

Então, no seu controlador principal, você pode manipular o evento:

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

Você só precisa declarar a diretiva em sua tag body:

           

Eu fiz o seguinte

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

      "Txtbinge"          

controllers.js

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

Veja isto: https://github.com/canemacchina/angular-google-client .

Escrevi este módulo para usar o Google Api ou o Google Cloud Endpoint em um aplicativo Angular.

Então eu estava tendo o mesmo problema. Colocando este código na minha fábrica funcionou

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

Basicamente, o problema é tentar chamar gapi.client antes de ser carregado. Se você apenas verificar que ele está carregado, e se não estiver, tente novamente em um segundo (você pode definir o tempo para o que quiser, configure-o para baixo se você espera que o usuário precise disso rapidamente depois que a página for carregada).

Eu estava lutando com isso por um tempo, e isso é tudo que funcionou para mim … Espero que isso ajude!

Eu usei uma solução semelhante ao willlma, mas meu aplicativo faz uso do roteador de interface do usuário, portanto, não há como saber qual controlador será chamado.

Consegui resolver isso com uma promise de JavaScript.

index.html

      

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