Google login for server-side apps - javascript

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.

Related

Loading Maps API with the jsapi loader is deprecated

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

Infinite loop on window.init() in GAE/Angular app

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.

How can I use the YouTube API inside an AMD module?

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?

How to call a javascript function defined in a script tag?

Example:
<script type="text/javascript">
function test() {
console.log("Hello world");
}
</script>
How would I call test()?
Edit: I didn't explain this correctly.
I am using the request module of node.js to load an external html file that contains javascript functions:
request.get(options, function (error, response, body) {
if (error && response.statusCode !== 200) {
}
else {
jsdom.env({
html: body,
scripts: ["../jquery-1.6.4.min.js"]
}, function (err, window) {
var $ = window.jQuery;
I'm just looking for the syntax to call a function in 'body'.
So the problem here is that by default, jsdom.env does not execute javascript found while processing markup.
You'll need to turn these features on:
jsdom.env({
// ...
features : {
FetchExternalResources : ['script'],
ProcessExternalResources : ['script']
}
});
FetchExternalResources controls whether or not jsdom should even bother reaching across the network/disk to collect the bytes of a resource
ProcessExternalResources controls whether or fetched scripts are executed
Note these names were chosen to encompass other resources types (read: images, css, etc..) which will be added in the future. The idea here is to provide sane defaults, but have many turnable knobs that affect the behavior of jsdom.
Just call it like any other function on your page, jQuery is a framework and is not needed for running a JS function.
hmmm... probably I'd go with
test();
But that's not jquery, it's plain old javascript.
Try this:
...
function (err, window) {
var $ = window.jQuery;
window.test();
...
You could also try:
<script type="text/javascript" id="myscript">
function test() {
console.log("Hello world");
}
</script>
And then:
function (err, window) {
var $ = window.jQuery;
(1,window.eval)( $("#myscript").html() );
window.test();

Javascript / Jquery functions

Not sure if I am being totally wrong here but I want to do something like this:
Have an external js page (on an external server)
Include the page - OK that is easy etc...
Have a Jquery function on the external page - well actually many functions
Call those functions directly onto the page.
All a bit like this:
External js page:
$(document).ready(function() {
function testit() {
$('#test').load('page.php');
}
function testit_1() {
$('#test_1').load('page_1.php');
}
function testit_1() {
$('#test_2').load('page_2.php');
}
});
Then on the actual page just call:
<script type="script/javascript">
testit();
</script>
<div id="test"></div>
Am I wrong or should that not work?
You dont need to define the functions within the ready function, but you have to call it within the ready function.
$(document).ready(function() {
testit();
});
function testit() {
$('#test').load('page.php');
}
function testit_1() {
$('#test_1').load('page_1.php');
}
function testit_2() {
$('#test_2').load('page_2.php');
}
Otherwise testit() will be called before the document is loaded. And at that moment the function doesn't even exist yet in your example.
Your functions are local to the scope of the anonymous function passed as the argument to $(document).ready(). Here's a simple example showing the behaviour you're seeing:
(function() {
function foo() {
alert("It shouldn't alert this...");
}
})();
foo();
To fix it, simply move your function declarations outside of the ready function:
function testit() {
$('#test').load('page.php');
}
function testit_1() {
$('#test_1').load('page_1.php');
}
function testit_2() {
$('#test_2').load('page_2.php');
}
And use the ready function (shorthand $(function() { ... })) in your main js file:
$(function() {
testit_1();
});
I'm not sure if I'm understanding you wrongly, but will you load an external page of an external server? This is not possible on normal browser security settings. You cannot perform a succesful XMLHttpRequest for a document that resides on a different server. Nearly all browsers will block this and leave you with nothing. You would have to write a server-side proxy that fetches the document and serves it back to the client.
That should work fine. Just be sure to include the external JS file in your page and execute testit() inside another $.ready() call:
<script type="script/javascript" src="http://someurl.com/external.js"></script>
<script type="script/javascript">
$.ready( function() {
testit();
} );
</script>
<div id="test"></div>
The location of a JS file is irrelevant. Once it is loaded into your page, it is executed in the context of that page.

Categories