Angular Js 和 google api client.js (gapi)
Posted
技术标签:
【中文标题】Angular Js 和 google api client.js (gapi)【英文标题】:Angular Js and google api client.js (gapi) 【发布时间】:2013-10-24 07:57:25 【问题描述】:我花了一天的时间才使它起作用,所以我认为我的经验可能对某人有用。也许其他一些人会发现改进。
所以我两天前开始使用 angularJS。我希望它与 Google Cloud Endpoints 一起使用以创建后端界面。我的麻烦来了。
gapi 的 javascript 客户端带有异步加载,因此角度初始化会在 gapi 未定义的情况下崩溃。
所以你需要在 gapi 初始化时引导 angular:
-
删除 ng-app="myApp"
添加
<script src="https://apis.google.com/js/client.js?onload=googleOnLoadCallback"></script>
添加回调:
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 有转机吗?
【参考方案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 你的编辑被拒绝了,但它是正确的,所以我复制了它。谢谢。 无限循环***.com/questions/28732667/…怎么样? 在那里查看我的答案。 TLDR:为init
和initGapi
使用不同的函数名称
嗨,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);
);
);
【讨论】:
以上是关于Angular Js 和 google api client.js (gapi)的主要内容,如果未能解决你的问题,请参考以下文章
Angular 4:Google Places 自动完成 API 不起作用
CORS 和 Angular $http GET 到 Google Places API