Recently I see this message in the console logs:
Loading Maps API with the jsapi loader is deprecated.
This is the code which causes it:
connected: function() {
...
},
initComponent: function() {
var me = this;
google.load('maps', '3', {
other_params: 'key=YOUR_API_KEY',
callback : me.connected
});
...
}
Loading it statically this is not really an option for me, because callback=connected will call back to window.connected() instead of me.connected():
<script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=connected"></script>
What is the alternative to google.load(), while calling back into the local scope? The documentation at Loading the Maps JavaScript API only offers static loading.
When adding this function in the global scope:
window.connected = function() {
console.log("Maps API connected");
};
It shows that it is connected, long before the application even launched:
Maps API connected
Util.js:747 [V] the Application was launched.
So this probably is a non-issue. All I have to do is to call it afterender:
listeners: {
afterrender: function() {
appdata.items.panel.Maps.connected();
}
},
Related
I'm following the Google guide for signing in with Google and sending the access code to a server:
Guide here: https://developers.google.com/identity/sign-in/web/server-side-flow#step_6_send_the_authorization_code_to_the_server
I have two really simple questions:
How does the closure in the jQuery click event know about auth2? If you run this code in Chrome, you'll get an error saying auth2 is undefined. How would I go about fixing that error?
Run from onload:
function start() {
gapi.load('auth2', function() {
auth2 = gapi.auth2.init({...});
});
}
jQuery click handler
(function($) {
$('#signinButton').click(function() {
auth2.grantOfflineAccess({'redirect_uri': 'postmessage'}).then(signInCallback);
});
})(jQuery);
How is signInCallback passed information? Is this part of the callback process?
The code:
function signInCallback(authResult) {
if(authResult['code']) {
$.ajax({...});
} else { ... }
}
Loading the client api at the top of the HTML file:
<script src="https://apis.google.com/js/client:platform.js?onload=start" async defer></script>
and then initializing:
function start() {
gapi.load('auth2', function() {
auth2 = gapi.auth2.init({...});
});
}
also in the header will do the trick. The guide says this, but neglects to state that it won't really work otherwise.
I'm using the cloud enpoints demo with AngularJS and I'm running into an infinite loop with their suggested method of running the authorization after the client.js is loaded. Here is the suggested method.
First, after all other script tags (for Angular and other JS files, I'm doing this):
<script>
function init() {
window.init();
}
</script>
<script src="https://apis.google.com/js/client.js?onload=init"></script>
Then, in a controller, I handle the window init like:
$window.init = function () {
// Loads the OAuth and helloworld APIs asynchronously, and triggers login
// when they have completed.
var apisToLoad;
var callback = function () {
if (--apisToLoad == 0) {
googleAPI.signin(true,
googleAPI.userAuthed);
appContext.appReady = true;
alert('loaded');
}
}
apisToLoad = 2; // must match number of calls to gapi.client.load()
gapi.client.load('helloworld', 'v1', callback, googleAPI.apiRoot);
gapi.client.load('oauth2', 'v2', callback);
};
What I think I'm finding is that there is a race condition here where the $window.init is not set up early enough so I end up with the message:
Uncaught RangeError: Maximum call stack size exceeded
This is due to the fact that the "window.init()" just calls back to the init() function and exceeds the stack.
Any suggestions on how I can better handle this? Thanks.
The first line is creating an infinite loop there because you are calling window.init inside the actual window.init.
<script>
/**
* Initializes the Google API JavaScript client. Bootstrap the angular module after loading the Google libraries
* so that Google JavaScript library ready in the angular modules.
*/
function init() {
gapi.client.load('conference', 'v1', null, '//' + window.location.host + '/_ah/api');
gapi.client.load('oauth2', 'v2', callback);
};
</script>
<script src="//apis.google.com/js/client:plusone.js?onload=init"></script>
You can try this code to see if makes more sense for you
Looks like your angular controllers are not loading/executing in time, can't tell why but you could wait for document ready, in true jQuery fashion:
function init() {
angular.element(document).ready(function() {
window.init();
});
}
Angular should've finished loading by then.
By doing this, you're telling window.init to call itself, creating an infinite loop.
<script>
function init() {
window.init();
}
init===window.init; // => true
</script>
<script src="https://apis.google.com/js/client.js?onload=init"></script>
If you look at my code more closely, you'll see that I name the functions differently, like so:
<script>
function init() {
window.initGapi();
}
init===window.initGapi; // => false
</script>
<script src="https://apis.google.com/js/client.js?onload=init"></script>
Then simply define initGapi in your controller instead:
$window.initGapi = function () {}
The code in the comments to the accepted answer waits until the api is loaded to bootstrap the app, which takes longer.
Put this in the "I missed something really basic" bin:
I noticed that I forgot something in my controller definition:
topNavBar.$inject = ['$location', 'appContext', 'logger'];
function topNavBar($location, $window, appContext, logger) {
Notice, no '$window' in the inject, so it got the definition for appContext and doing a "$window.init = " had absolutely no effect.
I have a function which calls out for JSON and then in the success function makes some changes to the DOM. I'm trying to use the mock-ajax library in my Jasmine tests to avoid having to expose the various private functions for mocking.
Even though when stepping through the test the request.response is set the onSuccess method is never called.
My tests:
describe('the table loader', function () {
var request;
beforeEach(function() {
//html with a loader div, an output div and a transit and dwell template
setFixtures('<div class="loader"></div><div class="row"><div id="output" class="col-xs-12"></div></div><script id="thingTemplate" type="text/x-handlebars">{{snip}}</script>');
expect($('.loader')).toBeVisible();
//start ajax call
window.dashboards.thing.display({
loaderId: '.loader',
templateId: '#thingTemplate',
templateOutletId: '#output',
dataUrl: '/my/fake/url'
});
//catch the ajax request
request = mostRecentAjaxRequest();
});
describe('on success', function () {
beforeEach(function() {
//populate the response
request.response({
status: 200,
responseText: "{rowItem: [{},{},{}]}"
});
});
it('should hide the loader', function () {
//thing should now receive that JSON and act accordingly
expect($('.loader')).not.toBeVisible();
});
});
});
and my code:
(function (dashboards, $) {
dashboards.thing = dashboards.thing || {};
var compileTable = function(templateId, jsonContext) {
var source = $(templateId).html();
var template = Handlebars.compile(source);
var context = jsonContext;
return template(context);
};
var getDashboardData = function(options) {
$.getJSON(
options.dataUrl,
function (data) {
processDashboardData(options, data);
}
).fail(function (jqxhr, textStatus, error) {
console.log('error downloading dashboard data');
console.log(textStatus + ': ' + error);
}).always(function() {
console.log('complete');
});
};
var processDashboardData = function (options, data) {
$(options.loaderId).hide();
$(options.templateOutletId).html(compileTable(options.templateId, data));
};
dashboards.thing.display = function (options) {
getDashboardData(options);
};
}(
window.dashboards = window.dashboards || {},
jQuery
));
None of the deferred functions (success, error, and always) are being called.
Edit
based on #gregg's answer below (and he's right I didn't include the UseMock call in the example code) this feels like a versions issue. As even with that call included this still isn't working for me.
I've added a runnable example on github
You need to make sure to install the ajax mock with jasmine.Ajax.useMock() before you actually make the call or jasmine-ajax won't have taken over the XHR object and you'll be making real requests. Once I did that against your sample code, it looks like the responseText you're sending isn't JSON parsable and jQuery blows up. But I was still seeing the 'complete' message logged in my console.
So, as of 29th Jan 2014, the download link in the Readme for mock-ajax on Github in the 1.3.1 tag doesn't point to the correct version of the file.
Manually downloading the mock-ajax file from the lib folder of the tag does work.
In other words for the 1.3.1 tagged release don't download from the readme link download from the tag lib folder directly
It's possible that the format of the data returned by your ajax call and jasmine's is different -- I believe that would throw an exception that wouldn't be recoverable, hence the reason none of your callback functions are running.
Newer versions of jasmine-ajax also use request.respondWith, and it's also of note (although I think jQuery handles this), that Jasmine doesn't have XMLHttpRequest.Done defined, so if you use vanilla JS you have to handle this case yourself. Lastly I use jasmine.Ajax.install() and not jasmine.Ajax.useMock().
Whew -- it's hard to know what exactly to do because Jasmine has such poor documentation for older versions and there are so many inconsistencies across them.
The YouTube API expects certain functions to be attached to the window object. Which seems simple enough:
requirejs(function() {
console.log('i am being loaded')
window.onYouTubeIframeAPIReady = function() {
console.log('ready')
}
});
In this case, 'i am being loaded' is logged, but 'ready' is never shown.
I can see the correct function appears on window.onYouTubeIframeAPIReady from the browser console.
However a script tag works:
<script>
window.onYouTubeIframeAPIReady = function() {
console.log('ready from script tag')
}
</script>
Logs correctly.
What am I doing wrong? How can I use the YouTube API inside an AMD module?
I tried to load the Google APIs Client Library for JavaScript with requirejs and the async plugin:
require.config({
paths : {
async : '../lib/requirejs/async'
},
waitSeconds: 60
});
define('gapi', ['async!https://apis.google.com/js/client.js!callback'],
function(){
console.log('gapi loaded');
return gapi.client;
}
);
require(['gapi'], function(){
console.log("Callback");
console.log(gapi);
});
The usual way to load this library is
<script src="https://apis.google.com/js/client.js?onload=handleClientLoad"></script>
Everything is loaded in less than 2s but I always get this error:
Uncaught Error: Load timeout for modules: async!https://apis.google.com/js/client.js!callback_unnormalized2,async!https://apis.google.com/js/client.js!callback
http://requirejs.org/docs/errors.html#timeout
TL;DR; change the !callback to !onload that should fix the timeout.
define('gapi', ['async!https://apis.google.com/js/client.js!onload'],
function(){
console.log('gapi loaded');
return gapi.client;
}
);
The value after the ! is used as the argument name for the async callback, in this case the URI loaded will be something like https://apis.google.com/js/client.js?onload=__async_req_3__ where __async_req_3__ is a global variable (callback function) triggered as soon as the Google API is loaded (notifies the plugin that all dependencies are met).